For some reason, I'm getting multiple declarations of content within my header file even though I'm using header guards. My example code is below:
main.c:
#include "thing.h"
int main(){
printf("%d", increment());
return 0;
}
thing.c:
#include "thing.h"
int increment(){
return something++;
}
thing.h:
#ifndef THING_H_
#define THING_H_
#include <stdio.h>
int something = 0;
int increment();
#endif
When I attempt to compile this, GCC says that I have multiple definitions of the something variable. ifndef should make sure that this doesn't happen, so I'm confused why it is.
The include guards are functioning correctly and are not the source of the problem.
What happens is that every compilation unit that includes thing.h gets its own int something = 0, so the linker complains about multiple definitions.
Here is how you fix this:
thing.c:
#include "thing.h"
int something = 0;
int increment(){
return something++;
}
thing.h:
#ifndef THING_H_
#define THING_H_
#include <stdio.h>
extern int something;
int increment();
#endif
This way, only thing.c will have an instance of something, and main.c will refer to it.
You have one definition in each translation unit (one in main.c, and one in thing.c). The header guards stop the header from being included more than once in a single translation unit.
You need to declare something in the header file, and only define it in thing.c, just like the function:
thing.c:
#include "thing.h"
int something = 0;
int increment(void)
{
return something++;
}
thing.h:
#ifndef THING_H_
#define THING_H_
#include <stdio.h>
extern int something;
int increment(void);
#endif
The header guards will stop the file from being compiled more than once in the same compilation unit (file). You are including it in main.c and thing.c, so it will be compiled once in each, leading to the variable something being declared once in each unit, or twice in total.
try to avoid defining variables globally.
use functions like increment() to modify and read its value instead.
that way you can keep the variable static in the thing.c file, and you know for sure that only functions from that file will modify the value.
The variable something should be defined in a .c file, not
in a header file.
Only structures, macros and type declarations for variables and function prototypes
should be in header files. In your example, you can declare the type of something as extern int something in the header file. But the definition of the variable itself should be in a .c file.
With what you have done, the variable something will be defined
in each .c file that includes thing.h and you get a
"something defined multiple times" error message when GCC tries to link
everything together.
what ifndef is guarding is one .h included in a .c more than once. For instance
thing. h
#ifndef
#define
int something = 0;
#endif
thing2.h
#include "thing.h"
main.c
#include "thing.h"
#include "thing2.h"
int main()
{
printf("%d", something);
return 0;
}
if I leave ifndef out then GCC will complain
In file included from thing2.h:1:0,
from main.c:2:
thing.h:3:5: error: redefinition of ‘something’
thing.h:3:5: note: previous definition of ‘something’ was here
Related
I have the problem, that in CCS I encounter unexpected redefenition errors if I include headers.
Minimal example:
// main.c
#include "test.h"
int main(void)
{
init();
return 0;
}
with
// test.h
#ifndef TEST_H_
#define TEST_H_
int var;
void init();
#endif /* TEST_H_ */
and
// test.c
#include "test.h"
void init()
{
var=0;
}
I get
error #10056: symbol "_var" redefined: first defined in "./main.obj";
redefined in "./test.obj"
on compilation. I'm pretty sure this should work in any C using IDE.
What do I miss?
" I'm pretty sure this should work in any C using IDE". No it doesn't.
Every time you include test.h in a C file, the variable var is not only declared but also defined, hence the compilation error.
Include guards are not designed to avoid multiple definitions across translation units, but more to adress multiple inclusions of the same header file in a single translation unit.
See for example https://fr.wikipedia.org/wiki/Include_guard
The proper way to adress this issue is to only declare your variable in the header file:
extern int var;
and then define the variable only once in a C file (without extern).
int var;
A toy code illustrating my problem is as follows:
stuff.h:
#ifndef STUFF
#define STUFF
int a;
int testarr[]={1,2,3};
#endif
fcn.h:
#include "stuff.h"
int b[]={5,6,7};
void fcn();
main.h:
#include "stuff.h"
#include <stdio.h>
fcn.c:
#include "main.h"
void fcn() {
printf("Hello\n");
}
main.c:
#include "main.h"
#include "fcn.h"
int main() {
fcn();
printf("HI\n");
}
An attempt to compile fails with:
/g/pe_19976/fcn_2.o:(.data+0x40): multiple definition of `testarr'
/g/pe_19976/main_1.o:(.data+0x40): first defined here
After doing some reading, I realize that defining the array testarr in the header file is a problem. But the thing is, in my real code, several files need access to testarr and it needs to have the same assigned values everywhere. I guess I could put it in main.h (?) but even if that would work, in my real code it logically belongs in stuff.h. How do I solve this conundrum?
BTW, based on something else I found, I tried defining testarr as extern but got the same problem.
When you put a variable definition into a header file, any .c file that includes it will have a copy of that variable. When you then attempt to link them, you get a multiple definition error.
Your header files should contain only a declaration of the variable. This is done using the extern keyword, and with no initializer.
Then in exactly one .c file, you put the definition along with an optional initializer.
For example:
main.c:
#include "main.h"
#include "fcn.h"
int a;
int testarr[]={1,2,3};
int main() {
fcn();
printf("HI\n");
}
stuff.h:
#ifndef STUFF
#define STUFF
extern int a;
extern int testarr[];
#endif
fcn.h:
#include "stuff.h"
extern int b[];
void fcn();
fcn.c:
#include "main.h"
int b[]={5,6,7};
void fcn() {
printf("Hello\n");
}
It is not clear why you are using so many global variables. The array
int testarr[]={1,2,3};
is defined as many times as there are compilation units (in your example there are at least two compilation units) that include the corresponding header.
Declare the array in a header like
extern int testarr[3];
and define it in a cpp module.
int testarr[]={1,2,3};
The same is valid for other global variables that have external linkage.
As for this remark
BTW, based on something else I found, I tried defining testarr as
extern but got the same problem.
Then the array with the specifier extern shall not be initialized in a header. Otherwise it is a definition of the array.
I have defined an enum in a header file,
global.h:
Typedef enum
{
ELEMENT1,
ELEMENT2,
ELEMENT3
}e_element;
I have a second file using the enum as a function parameter.
file2.c
#include global.h
#include file2.h
Function(e_element x)
{
Body…
}
The prototype is in:
file2.h
Function(e_element x);
The compiler doesn’t know e_element in file2.h. I have tried putting the #include for global.h in both file2.c and file2.h, but it still doesn’t see it. I would put the enum in file2.h, except that it is used by several other files, so if I move it the problem will just show up somewhere else.
How can I get the file2.h prototype to see e_element?
This worked for me:
global.h
#ifndef GLOBAL_H
#define GLOBAL_H
typedef enum
{
ELEMENT1,
ELEMENT2,
ELEMENT3
}e_element;
#endif
file2.h
#ifndef FILE_2_H
#define FILE_2_H
#include "global.h"
int test(e_element);
#endif
file2.c
#include "file2.h"
int test(e_element x)
{
return x == ELEMENT1;
}
int main() {
return 0;
}
edit:
#ifndef is conventionally used as a "header guard". It prevents a header file from being included multiple times by the preprocessor, which prevents things from being defined multiple times. It works by checking if a unique symbol has been defined before. If it has not, then it immediately defines it and then continues with the header file until #endif. If the symbol was already defined then it skips the guarded code completely, preventing multiple definitions. An example of multiple definitions would be if the same header file was included in a source and a header that the source also includes.
See this link for more information.
I keep getting a linker error with the following setup.
I have file1.c which contains the following code
#if defined( _TEST_ENABLED )
int get_value()
{
.
.
.
}
#endif /*_TEST_ENABLED */
I have file2.c which includes file2.h, which defines _TEST_ENABLED. file2.c makes a call to get_value(), however the linker isn't having any part of that.
I've exhausted a lot of different options with zero success. Now i'm asking for help :)
If file1.c does not include file2.h or any file which defines _TEST_ENABLED, _TEST_ENABLED will not be defined when the preprocessor runs on file1.c, so int get_value() { ... } will not get compiled.
In order to call a function in another file:
1) The files must be compiled or at least linked together. The easiest way to do this is gcc file1.c file2.c, however you can also compile both files to *.o files and then link together.
2) The calling file must have, usually through an included header, a prototype of the function. This prototype must appear before the function is used. So, if file2.h defines _TEST_ENABLED, then you must (in file2.c) include file2.h, and then either file2.c or file2.h must include file1.h, which must contain a function prototype (int get_value;)
For example:
file1.c
#include <file1.h>
#include <file2.h>
int main() {
get_value();
}
file1.h
#ifndef _FILE2_H
#define _FILE2_H
#define _TEST_ENABLED
#endif
file2.c
#include <file2.h>
#include <file1.h>
#ifdef _TEST_ENABLED
int get_value() {
return 42;
}
#endif
file2.h
#ifndef _FILE2_H
#define _FILE2_H
int get_value();
#endif
Note that for the purposes of the preprocessor, file1.c and file2.c are processed completely separately. When processing file2.c, it MUST find #define _TEST_ENABLED somewhere, which is why file2.c must include file1.h. Since this is getting a little circular, you should add "#include-guards to each header file, as shown above.
There are some ambiguities in your question, but given the following three files, I can compile and build in ANSI C, but I have to include the .h in both .cs:
file1.c
#include "file2.h"
int main(void)
{
someFunc();
get_value();
return 0;
}
#ifdef _TEST_ENABLED
int get_value(void)
{
return 0;
}
#endif
file2.c
#include "file2.h"
int someFunc(void);
int someFunc(void)
{
get_value();
return 0;
}
file2.h
#define _TEST_ENABLED
int get_value(void);
I'm trying to understand how global variables and functions work in C. My program compiles and works fine with gcc, but does not compile with g++. I have the following files:
globals.h:
int i;
void fun();
globals.c:
#include "stdlib.h"
#include "stdio.h"
void fun()
{
printf("global function\n");
}
main.c:
#include "stdlib.h"
#include "stdio.h"
#include "globals.h"
void myfun();
int main()
{
i=1;
myfun();
return 0;
}
And finally, myfun.c:
#include "stdlib.h"
#include "stdio.h"
#include "globals.h"
void myfun()
{
fun();
}
I get the following error when compiling with g++:
/tmp/ccoZxBg9.o:(.bss+0x0): multiple definition of `i'
/tmp/ccz8cPTA.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status
Any ideas why? I would prefer to compile with g++.
Every file you include globals.h from will define "int i".
Instead, put "extern int i;" into the header file and then put the actual definition of "int i = 1;" in globals.c.
Putting header guards around globals.h would be sensible too.
Edit: In answer to your question its because a #include works kind of like a cut and paste. It pastes the contents of the included file into the c file that you are calling include from. As you include "globals.h" from main.c and myfun.c you define int i = 1 in both files. This value, being global, gets put into the table of linkable values. If you have the same variable name twice then the linker won't be able to tell which one it needs and you get the error you are seeing. Instead by adding extern on the front in the header file you are telling each file that "int i" is defined somewhere else. Obviously, you need to define it somewhere else (and ONLY in one place) so defining it in globals.c makes perfect sense.
Hope that helps :)
I would add an include guard in your globals file
#ifndef GLOBALS_H
#define GLOBALS_H
int i;
void fun();
#endif
Edit: Change your globals to be like this (using extern as the other answer describes)
globals.h
extern int i;
extern void fun();
globals.c
#include "stdlib.h"
#include "stdio.h"
int i;
void fun()
{
printf("global function\n");
}
I compiled it with
g++ globals.c main.c myfun.c
and it ran ok
Several things wrong here; several other things highly recommended:
globals.h:
#ifndef GLOBALS_H
#define GLOBALS_H
extern int my_global;
#ifdef __cplusplus
extern "C" {
#endif
void fun();
#ifdef __cplusplus
}
#endif
#endif
/* GLOBALS_H */
globals.c:
#include <stdlib.h>
#include <stdio.h>
#include "globals.h"
int my_global;
void fun()
{
printf("global function: %d\n", my_global);
}
main.c:
#include <stdlib.h>
#include <stdio.h>
#include "globals.h"
void myfun();
int main()
{
my_global=1;
myfun();
return 0;
}
void myfun()
{
fun();
}
You should declare "extern int myvar" in your header, and actually allocate "int myvar" in one and only one .c file.
You should include "globals.h" in every file that uses "myvar" - including the file where it's allocated.
Especially if you're planning on mixing C and C++ modules, you should use 'extern "C"' to distinguish non-C++ functions.
System headers should be "#include <some_header.h>"; your own headers should use quotes (#include "myheader.h") instead.
Short variable names like "i" might be OK for a strictly local variable (like a loop index), but you should always use longer, descriptive names whenever you can't avoid using a global variable.
I added a "printf" for my_global.
'Hope that helps!
I had this problem when porting some old C code to C++. The problem was it was a project that was connected to a database, and i wanted to port the database to c++ but not the rest. The database pulled in some C dependencies that couldn't be ported, so i needed the C code that overlapped both the database and the other project to compile in g++ as well as gcc...
The solution to this problem is to define all variables as extern in the .h file. then when you compile in either gcc or g++ it will report symbols missing in the .c files. So edit the .c files in the error messages and insert the declaration into all the .c files that need the variables. Note: you may have to declare it in multiple .c files, which is what threw me and why I was stuck on this problem for ages.
Anyway this solved my problem and the code compiles cleanly under both gcc and g++ now.