I am programming a game in C using Code::Blocks. I am using the most recent version of C and of Code::Blocks. I am still learning the language.
All of my past programs have been contained in one huge source file, so I decided to branch out and try putting my code in multiple files. I know that the proper way to do it is to have source files containing code definitions and such and a header file containing prototypes for other source files to use. This has worked out horribly for me and I either can't get the files to work together properly or it simply doesn't work period.
I have a single function in a source file called process.c and a function prototype in a file called process.h. I also have a main.h and a main.c containing all the rest of the code. The main issue is that I have a typedef struct Game in my main.h file and I can't get the 'Game' struct type I created to work in my process.c. Every function in my game needs the Game type in order to work. However, when I give process.c access to main.h (the file that Game is declared in) I get issues.
My code works fine when it's in one file. My header files are protected from duplication and are properly included in the program. The problem is, I need to include main.h in both main.c and process.c. And I have to include process.h in both 'main.c' and 'process.c'. I have tried every configuration and nothing works.
In some #include configurations I get no errors, but I get this weird message that says "It seems your project has not been built yet; would you like to build it now?" and when I click "Yes" nothing happens.
My compiler works fine and there is nothing wrong with the projects settings. What the heck is going on here? How do I get main.h and process.h to work together?
EDIT: Source code:
main.c:
#include <stdio.h>
#include "main.h"
#include "process.h"
void initGame(Game *thisGame)
{
variable = 10;
number = 5;
letter = 'c';
}
int main()
{
Game thisGame;
initGame(&thisGame);
displayData(&thisGame);
return 0;
}
main.h:
#ifndef _MAIN_H_
#define _MAIN_H_
typedef struct
{
int variable, number;
char letter;
}
#endif
process.c:
#include <stdio.h> //not sure if this should be here or not, it doesn't seem to effect my code
#include "main.h"
#include "process.h"
void displayData(Game *thisGame)
{
printf("%i, %i, %c", thisGame.variable, thisGame.number, thisGame.letter);
}
process.h:
#ifndef _MAIN_H_
#define _MAIN_H_
void displayData(Game *thisGame);
#endif
Error message
-------------- Build: Debug in FishKiller (compiler: GNU GCC Compiler)---------------
mingw32-g++.exe -L..\deps\lib -L..\SDLFILES\lib -o bin\Debug\FishKiller.exe obj\Debug\main.o obj\Debug\process.o -lmingw32 -lSDL2main -lSDL2 -lSDL2_image
obj\Debug\process.o:process.c:(.rdata+0x0): multiple definition of `SCREEN_WIDTH'
obj\Debug\main.o:main.c:(.rdata+0x0): first defined here
obj\Debug\process.o:process.c:(.rdata+0x4): multiple definition of `SCREEN_HEIGHT'
obj\Debug\main.o:main.c:(.rdata+0x4): first defined here
obj\Debug\process.o:process.c:(.rdata+0x8): multiple definition of `GAMESTATE_MENU'
obj\Debug\main.o:main.c:(.rdata+0x8): first defined here
obj\Debug\process.o:process.c:(.rdata+0xc): multiple definition of `GAMESTATE_GAME'
obj\Debug\main.o:main.c:(.rdata+0xc): first defined here
obj\Debug\process.o:process.c:(.rdata+0x10): multiple definition of `GAMESTATE_GAMEOVER'
obj\Debug\main.o:main.c:(.rdata+0x10): first defined here
collect2.exe: error: ld returned 1 exit status
Process terminated with status 1 (0 minute(s), 0 second(s))
0 error(s), 0 warning(s) (0 minute(s), 0 second(s))
Issues are address file by file below. Once these issues are corrected in your source, the executable will build.
1)
In process.h you have the wrong header blocks:
#ifndef _MAIN_H_
#define _MAIN_H_
//Change to:
#ifndef _PROCESS_H_
#define _PROCESS_H_
Also change:
void displayData(Game *thisGame);(see notes in main.h for explanation)
To:
void displayData(GAME *thisGame);
2) In process.c you have;
#include "main.h"
It does not hurt anything, but since we are analyzing everything, it is not needed to support current architecture.
You also have:
printf("%i, %i, %c", thisGame.variable, thisGame.number, thisGame.letter);
Because the thisGame is passed in as a pointer, you need to use struct pointer operator: ->
printf("%i, %i, %c", thisGame->variable, thisGame->number, thisGame->letter);
Also, the function protocol in the same file is incorrect. You are attempting to instantiate a variable type that does not exist: (see notes for main.h)
Change:
void displayData(Game *thisGame){...}
To:
void displayData(GAME *thisGame){...}//uses typedef struct GAME
3) in main.h you have a malformed struct:
typedef struct
{
int variable, number;
char letter;
}//no ";" statement terminator to indicate to your compiler _end of struct_
And with this definition, there is no struct name with which to reference or instantiate it in any other file. Change it to the following:
typedef struct
{
int variable;
int number;//style point , put each member on its own line
char letter;
}GAME;//note struct type name and terminator ";"
With the struct type name, in this case GAME, you can create instances of this struct in any file that #includes this file.
extern GAME Game;// using the extern modifier, create an instance of GAME
// that can be referenced in any file of the
//project, once initialized. (See the line GAME Game; in main.c)
4) in main.c you have variables in the function initGame that need to be referenced differently. Change this:
void initGame(Game *thisGame)
{
variable = 10;
number = 5;
letter = 'c';
}
To:
void initGame(GAME *thisGame)
{
thisGame->variable = 10;
thisGame->number = 5;
thisGame->letter = 'c';
}
There is Code::Blocks information here that may help you to set up your environment to get the error messages that will help you to debug your code.
Related
I creating a program in c language and i using the Visual Studio Code for the first time, my functions in the header files don't function. This is my code in main:
#include <stdio.h>
#include "PilhaDinamica.h"
#include "PilhaEstatica.h"
int main()
{
Pilha *p = criaPilha();
return 0;
}
And this is my .h file:
#ifndef PILHADINAMICA_H_INCLUDED
#define PILHADINAMICA_H_INCLUDED
typedef struct Nodo{
char info;
struct Nodo*prox;
} nodo;
typedef struct {
nodo * Topo;
} Pilha;
Pilha * criaPilha();
int pilha_vazia(Pilha *p);
void push(Pilha *p, char times);
char pop(Pilha *p);
#endif
This is my file with the functions:
#include "PilhaDinamica.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Pilha *criaPilha()
{
Pilha *p = (Pilha*) malloc(sizeof(Pilha));
p->Topo = NULL;
return p;
}
And this is shown in my output: "...\AppData\Local\Temp\ccmjk1nS.o:main.c:(.text+0xf): undefined reference to `criaPilha'
collect2.exe: error: ld returned 1 exit status"
what can i do to make it compile correctly?
As a general rule of thumb, header files (*.h) contains declarations (type, variable and function declarations) and source files (*.c) the definitions of those declarations.
At the compilation step, only source files will be compiled (because the definitions are there). A program or library creation is a 2 (actually more, like preprocessing and more but for simplicity we keep it at 2) step process:
creating object files
e.g. gcc -c -o object_file_name.o source_file_name.c
link those object files into an executable or static/shared library
e.g. gcc -o program_or_library_name object_file_1.o object_file_2.o ...
So, in your case you have to call the compiler two times for your source files (with the -c flag) and once to link those created object files into an executable.
Note: If you're using a different compiler other than gcc, have a look at the documentation on how to create object files and link them together.
below is the code:
//test.h
...
extern int globalVariable;
...
//test.c
#include "test.h"
...
int globalVariable = 2020;
...
//main.c
#include <stdio.h>
#include "test.h"
int main()
{
printf("Value is %d", globalVariable);
}
let's say in a scenario, there are hundreds of variables are declared in test.h and globalVariable is just one of them.
since there are two many variables, I easily makes a typo error in test.c as:
#include "test.h"
int globalVariables = 2020; //extra 's' in the name which contradicts the declaration of its counterpart in test.h
if I compile(only compile,not linking them) test.c, test.h and main.c, it compiles and shows no error. the unresolved error will only occur when linker involved in the linking stage.
But in a large application, I might just write some modules without the need of linking all existing to an executable file, so it would be better the compiler throw an error in the compile stage to indicate the error so I can correct them asap, so how can I let the compiler force the source file implement definition for a header file?
You could also use the preprocessor
test.h:
#ifndef TEST_C_IMPLEMENTATION
#define DEFINE_AND_INIT_VARIABLE(type, name, value) \
extern type name;
#else
#define DEFINE_AND_INIT_VARIABLE(type, name, value) \
type name = value;
#endif
DEFINE_AND_INIT_VARIABLE(int, globalVariable, 2020);
test.c:
#define TEST_C_IMPLEMENTATION
#include "test.h"
This technique can be taken even further - there are small utility libraries that are shipped as a single include file; you're just to set a macro in one of the translation units to force the implementation to be compiled in there.
The declaration extern int globalVariable; says that the variable exists somewhere, but not necessarily in the current translation unit. So any source file that includes the header containing this declaration will know that the variable exists without needing the full definition.
When you then get to the linking stage is when you'll get the error regarding glovalVariable being undefined. Since the variables is declared in test.h, convention would dictate that the definition would be in test.c. Upon inspecting that file, you would then find that no such variable exists and could then either add it or find the typo and fix it.
This is my header file, tree.h
#ifndef TREE_H_
#define TREE_H_
#if defined treeItem
extern int totalnode;
treeItem *addItem(treeItem *node, char *w);
void printInOrder(treeItem *node, FILE *output);
void freeTree(treeItem *node);
#endif
#endif
This is the main() in main.c which include tree.h
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "tree.h"
#define MAX 1024
extern int totalnode;
int main(int argc, char *argv[]){
FILE *input;
FILE *output;
char *filename;
char ch[MAX];
//extern int totalnode;
struct treeItem *element;
element = NULL;
int i;
if (argc > 2){
output = fopen(argv[1], "w");
for(i = 2; i < argc + 1; i++){
filename = argv[i];
input = fopen(filename, "r");
if(input != NULL){
while(getword(ch, MAX, input) != EOF)
if (isalpha(ch[0]))
element = addItem(element, ch);
}
}
printInOrder(element, output);
fprintf(output,"-------------- \n ");
fprintf(output,"%4d Total number of different words",totalnode);
freeTree(element);
fclose(input);
fclose(output);
}
else{
printf("There is no input file.\n");
}
return 0;
}
compiler says:
../main.c: In function 'main':
../main.c:57: warning: implicit declaration of function 'addItem'
../main.c:57: warning: assignment makes pointer from integer without a cast
../main.c:60: warning: implicit declaration of function 'printInOrder'
../main.c:64: warning: implicit declaration of function 'freeTree'
another error: Undefined symbols for architecture x86_64:
"_totalnode", referenced from:
_main in main.o
_addItem in tree.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
If I put all code in the same .c file without using header file, it works. But for now, it doesn't work. How can I fix it?
The line
#if defined treeItem
and the matching #endif should be removed from tree.h
Remember that preprocessing occurs conceptually before (or as the very first step of) the real compilation.
In general, you could have obtained the preprocessed form of main.c with
gcc -C -E main.c > main.i
and then look (e.g. with a pager like less) inside main.i
I often remove the generated preprocessor directives with
gcc -C -E main.c | grep -v '^#' > main.i
gcc -Wall -c main.i
this gives error messages with line numbers referring inside main.i (not main.c or tree.h) which is sometimes useful to debug macros. Another useful option to gcc is -H: it shows every #include-d file
In order to use the tree.h file 'as-is', and have it define items as you expect, you will have to define treeItem:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
/* You will need to define 'treeItem' prior to including 'tree.h'. */
typedef /* the defintition here */ treeItem;
#include "tree.h"
#define MAX 1024
extern int totalnode;
If you have the liberty of editing the tree.h file, it would probably be better to remove the line:
#if defined treeItem
and one of the lines:
#endif
Because you have pre compiler directives which exclude the substantive body of tree.h unless treeItem is defined, you must #define treeItem prior to the inclusion of tree.h within main.c, this is due to the way that precompiler directives are processed. This will solve the immediate problem.
I see that in main.c you have the line: struct treeItem *element;
If I am interpreting correctly that you intended this to satisfy the #ifdef treeItem line in your header, then you are misunderstanding how these # lines are like a separate language to C/C++. These lines are called precompiler directives, or more casually macros. Macros are commands for the preprocesser which operates over text files prior to compilation, for the purposes of creating in memory a full source code that can be compiled into an object that can later be linked with others to form your program. The preprocessor's defines are different from definitions in C/C++, and they don't directly interact. This line about the struct is practically invisible to the preprocessor, it knows nothing about C/C++. You must define this treeItem using #define, prior to the #ifdef.
More aesthetically, your header file should not guard like this, because it is superfluous. The main.c module's #include "tree.h" line alone is enough to indicate the intention of including the substantive body of tree.h. You have an appropriate guard against repeated inclusions, but the second guard regarding the treeItem definition seems unnecessary and is the cause of this issue. This latter paragraph is simply reiterating what other's have said, and would be technically superfluous as well if it does not contribute to persuading you of this opinion, however avoiding hypocrisy the first paragraph is a solution to your issue that does not intrude on your decision regarding said opinion.
I have a confusion about external structs. I have to define a global instance of the struct in a file other than which the struct is defined (as a RAM variable which I do not know what it is exactly).
Below is an example that GCC can compile and it runs correct while Code Composer Studio gives compile-time errors.
I want to learn where the problem is, how GCC can compile, and where/how I should use the extern declaration.
Any comment would be appreciated.
person.h
#ifndef PERSON_H
#define PERSON_H
struct person {
int age;
};
typedef struct person PERSON;
void modifyPerson();
#endif // PERSON_H
personRam.h
#ifndef PERSONRAM_H
#define PERSONRAM_H
#include "person.h"
PERSON p1;
#endif // PERSONRAM_H
modifyPerson.c
#include "person.h"
#include "personRam.h"
void modifyPerson() {
p1.age = 10;
}
main.c
#include <stdio.h>
#include "person.h"
#include "personRam.h"
int main() {
modifyPerson();
printf("%d", p1.age);
return 0;
}
You should not get a compiler error, but a linker error, saying that p1 is defined multiple times. At least that's what I guess is the problem.
The reason is that you define the variable in a header file, which you then include in multiple source files. This means that the definition is in both source files (The preprocessor #include directive literally puts the contents of the header file in place of the include "statement").
If you declare the variable as extern in the header file, and define it in one source file it should work.
So in personRam.h
extern PERSON p1;
And in one of the source files:
PERSON p1;
On which operating system are you compiling, and for which target system?
For what it is worth, Linux (& Unix-es) and Windows have different linking semantics.
Read Levine's "Linkers & Loaders" book for details.
I am currently working on my first "serious" C project, a 16-bit vm. When I split up the files form one big source file into multiple source files, the linker (whether invoked through clang, gcc, cc, or ld) spits out a the error:
ld: duplicate symbol _registers in register.o and main.o for inferred
architecture x86_64
There is no declaration of registers anywhere in the main file. It is a uint16_t array if that helps. I am on Mac OS 10.7.3 using the built in compilers (not GNU gcc). Any help?
It sounds like you've defined a variable in a header then included that in two different source files.
First you have to understand the distinction between declaring something (declaring that it exists somewhere) and defining it (actually creating it). Let's say you have the following files:
header.h:
void printIt(void); // a declaration.
int xyzzy; // a definition.
main.c:
#include "header.h"
int main (void) {
xyzzy = 42;
printIt();
return 0;
}
other.c:
#include <stdio.h>
#include "header.h"
void printIt (void) { // a definition.
printf ("%d\n", xyzzy);
}
When you compile the C programs, each of the resultant object files will get a variable called xyzzy since you effectively defined it in both by including the header. That means when the linker tries to combine the two objects, it runs into a problem with multiple definitions.
The solution is to declare things in header files and define them in C files, such as with:
header.h:
void printIt(void); // a declaration.
extern int xyzzy; // a declaration.
main.c:
#include "header.h"
int xyzzy; // a definition.
int main (void) {
xyzzy = 42;
printIt();
return 0;
}
other.c:
#include <stdio.h>
#include "header.h"
void printIt (void) { // a definition.
printf ("%d\n", xyzzy);
}
That way, other.c knows that xyzzy exists, but only main.c creates it.