Header file included more than once?

P

Pietro Cerutti

Hi Group,

suppose test1.c, test2.c and test.h

/*** BEGIN TEST.H ***/
#ifndef _TEST_H
#define _TEST_H

typedef struct
{
unsigned int code;
const char *name;
} test_struct;

test_struct structs[NOF_STRUCTS] =
{
{ 12, "twelve" },
{ 11, "eleven" }
};

int test_func(void);

#endif /* !_TEST_H */
/*** END TEST.H ***/

/*** BEGIN TEST1.C ***/
#include <stdio.h>
#include "test.h"

int main(void)
{
return (0);
}
/*** END TEST1.C ***/

/*** BEGIN TEST2.C ***/
#include "test.h"

int test_func(void)
{
return (2);
}
/*** TEST2.C ***/
gcc -ggdb -o test test1.c test2.c
/var/tmp//ccZgBLuP.o(.data+0x0): multiple definition of `structs'
/var/tmp//ccLatz7e.o(.data+0x0): first defined here

Why is the header file parsed twice (and thus structs defined twice),
even when I started the header file with #ifndef etc etc statements?

Thank you!
 
M

Mark Bluemel

Pietro said:
Hi Group,

suppose test1.c, test2.c and test.h

/*** BEGIN TEST.H ***/
#ifndef _TEST_H
#define _TEST_H

typedef struct
{
unsigned int code;
const char *name;
} test_struct;

test_struct structs[NOF_STRUCTS] =
{
{ 12, "twelve" },
{ 11, "eleven" }
};

int test_func(void);

#endif /* !_TEST_H */
/*** END TEST.H ***/

/*** BEGIN TEST1.C ***/
#include <stdio.h>
#include "test.h"

int main(void)
{
return (0);
}
/*** END TEST1.C ***/

/*** BEGIN TEST2.C ***/
#include "test.h"

int test_func(void)
{
return (2);
}
/*** TEST2.C ***/

gcc -ggdb -o test test1.c test2.c

/var/tmp//ccZgBLuP.o(.data+0x0): multiple definition of `structs'
/var/tmp//ccLatz7e.o(.data+0x0): first defined here

Why is the header file parsed twice (and thus structs defined twice),

because the header file is included in two independent source files
which are compiled individually.
 
J

Jens Thoms Toerring

Pietro Cerutti said:
suppose test1.c, test2.c and test.h
/*** BEGIN TEST.H ***/
#ifndef _TEST_H
#define _TEST_H
typedef struct
{
unsigned int code;
const char *name;
} test_struct;
test_struct structs[NOF_STRUCTS] =
{
{ 12, "twelve" },
{ 11, "eleven" }
};
int test_func(void);
#endif /* !_TEST_H */
/*** END TEST.H ***/
/*** BEGIN TEST1.C ***/
#include <stdio.h>
#include "test.h"
int main(void)
{
return (0);
}
/*** END TEST1.C ***/
/*** BEGIN TEST2.C ***/
#include "test.h"
int test_func(void)
{
return (2);
}
/*** TEST2.C ***/
/var/tmp//ccZgBLuP.o(.data+0x0): multiple definition of `structs'
/var/tmp//ccLatz7e.o(.data+0x0): first defined here
Why is the header file parsed twice (and thus structs defined twice),
even when I started the header file with #ifndef etc etc statements?

You already got the answer, i.e. the files test1.c and test2.c get
compiled individually and a macro set in test1.c (via the included
file) doesn't exist anymore when the compiler is restarted to
compile test2.c and you thus end up with two instances of structs.

To avoid that never, ever define variables (or anything else) in
a header file. Define structs in one of the .c files and declare
it as extern in the other (or in the header file, it doesn't hurt
if a variable is both declared as extern and defined). An extern
declaration doesn't create an instance of structs, it just tells
the compiler that it is defined somewhere else, so it won't com-
plain that the variable doesn't exist.

Regards, Jens
 
C

CBFalconer

Pietro said:
suppose test1.c, test2.c and test.h

/*** BEGIN TEST.H ***/
#ifndef _TEST_H
#define _TEST_H

typedef struct
{
unsigned int code;
const char *name;
} test_struct;

test_struct structs[NOF_STRUCTS] =
{
{ 12, "twelve" },
{ 11, "eleven" }
};

int test_func(void);

#endif /* !_TEST_H */
/*** END TEST.H ***/

/*** BEGIN TEST1.C ***/
#include <stdio.h>
#include "test.h"

int main(void)
{
return (0);
}
/*** END TEST1.C ***/

/*** BEGIN TEST2.C ***/
#include "test.h"

int test_func(void)
{
return (2);
}
/*** TEST2.C ***/
gcc -ggdb -o test test1.c test2.c
/var/tmp//ccZgBLuP.o(.data+0x0): multiple definition of `structs'
/var/tmp//ccLatz7e.o(.data+0x0): first defined here

Why is the header file parsed twice (and thus structs defined twice),
even when I started the header file with #ifndef etc etc statements?

Because the ifndef statements only apply to the individual
compiles. You have committed the ultimate sin of defining a data
object in a header file. gcc is performing two compiles and then
calling the linker module.
 
K

Keith Thompson

Pietro Cerutti said:
suppose test1.c, test2.c and test.h
[snip]

Others have given you correct answers, but here's another way to
look at it.

'#include' merely does textual substitution in a source file. You can
always achieve exactly the same effect by including the text directly
in your source file; it all looks the same to the compiler. (Well,
almost; system headers can be special, but that's not what we're
dealing with here.)

You've declared an object in your header file, then '#include'd the
header file in two different source files, then compiled and linked
the two source files into a program.

It's exactly as if you hadn't used a header file at all:

=== test1.c ===
/* ... */
test_struct structs[NOF_STRUCTS] =
{
{ 12, "twelve" },
{ 11, "eleven" }
};

int main(void)
{
return 0;
}
=== end of test1.c ===

=== test2.c ===
/* ... */
test_struct structs[NOF_STRUCTS] =
{
{ 12, "twelve" },
{ 11, "eleven" }
};
=== end of test2.c ===

Both of these compile ok (assuming you fill in the "..." correctly),
but when you invoke the linker to build your program, it sees two
definitions of the object 'structs'.

The header file didn't actually cause the problem; it's just the tool
you used to create the problem.

You need to *define* 'structs' exactly once in your entire program.
You can *declare* it (with 'extern') as many times as you need to. (A
definition actually creates the object. A declaration declares that
the object exists, but it may or may not create it. All definitions
are declarations, but not all declarations are definitions.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top