Why not a redefinition?

B

Bo Yang

Hi,
Look the following c program, why there is a redefinition of "t"?

[struggleyb@cache duplite-delcare]$ cat inc.h
#ifndef INC
#define INC
struct test{
int ok;
};

extern struct test t;

#endif


[struggleyb@cache duplite-delcare]$ cat test1.c
#include <stdio.h>
#include "inc.h"

struct test t;

int main(int argc, char ** argv)
{
ttt();
printf("t.ok in test1: %d\n", t.ok);
test3();
return 0;
}

[struggleyb@cache duplite-delcare]$ cat test2.c
#include <stdio.h>
#include "inc.h"

struct test t;

void ttt()
{
t.ok=1000;
printf("t.ok in test2: %d\n", t.ok);
}

[struggleyb@cache duplite-delcare]$ cat test3.c
#include <stdio.h>
#include "inc.h"

void test3()
{
printf("t.ok in test3: %d\n", t.ok);


}
[struggleyb@cache duplite-delcare]$ gcc34 -o test test3.c test2.c
test1.c
[struggleyb@cache duplite-delcare]$ ./test
t.ok in test2: 1000
t.ok in test1: 1000
t.ok in test3: 1000

At least, I define two copy of t, why there is no redefinition error?
Thanks!

Regards!
Bo
 
N

Nate Eldredge

Bo Yang said:
Hi,
Look the following c program, why there is a redefinition of "t"?

[struggleyb@cache duplite-delcare]$ cat inc.h
#ifndef INC
#define INC
struct test{
int ok;
};

extern struct test t;

#endif


[struggleyb@cache duplite-delcare]$ cat test1.c
#include <stdio.h>
#include "inc.h"

struct test t;

int main(int argc, char ** argv)
{
ttt();
printf("t.ok in test1: %d\n", t.ok);
test3();
return 0;
}

[struggleyb@cache duplite-delcare]$ cat test2.c
#include <stdio.h>
#include "inc.h"

struct test t;

void ttt()
{
t.ok=1000;
printf("t.ok in test2: %d\n", t.ok);
}

[struggleyb@cache duplite-delcare]$ cat test3.c
#include <stdio.h>
#include "inc.h"

void test3()
{
printf("t.ok in test3: %d\n", t.ok);


}
[struggleyb@cache duplite-delcare]$ gcc34 -o test test3.c test2.c
test1.c
[struggleyb@cache duplite-delcare]$ ./test
t.ok in test2: 1000
t.ok in test1: 1000
t.ok in test3: 1000

At least, I define two copy of t, why there is no redefinition error?

Technically, I think that

struct test t;

constitutes a "tentative definition" of t. See 6.9.2. In order for it
to be an external definition, it would have to have an initializer. But
if you have one or more tentative definitions and no external
definition, the compiler acts as if there were a file scope declaration
initialized to zero (which would be an external definition).

So it does appear to have the effect of there being a definition,
initialized to zero, in each file (translation unit). 6.9 (5) would
appear to forbid this, unless I am misreading it.

However, I know that it is commonly accepted by compilers: they will
allow you to have a "tentative definition" of an object in each file.
Then the effect of having `struct test t;' without an initializer in several
files is equivalent to having `extern struct test t;' in each of them,
and `struct test t = { 0 };' in one of them. This is often implemented
with an object file feature called a "common section"; the linker
produces one copy of the object, containing zeros, and all references to
the symbol refer to that single object.

So maybe it's technically an extension to the C language.
 
F

Flash Gordon

Nate Eldredge wrote, On 13/12/08 07:09:
Bo Yang said:
Hi,
Look the following c program, why there is a redefinition of "t"?

[struggleyb@cache duplite-delcare]$ cat inc.h
#ifndef INC
#define INC
struct test{
int ok;
};

extern struct test t;

#endif


[struggleyb@cache duplite-delcare]$ cat test1.c
#include <stdio.h>
#include "inc.h"

struct test t;

int main(int argc, char ** argv)
{
ttt();
printf("t.ok in test1: %d\n", t.ok);
test3();
return 0;
}

[struggleyb@cache duplite-delcare]$ cat test2.c
#include <stdio.h>
#include "inc.h"

struct test t;

void ttt()
{
t.ok=1000;
printf("t.ok in test2: %d\n", t.ok);
}

[struggleyb@cache duplite-delcare]$ cat test3.c
#include <stdio.h>
#include "inc.h"

void test3()
{
printf("t.ok in test3: %d\n", t.ok);


}
[struggleyb@cache duplite-delcare]$ gcc34 -o test test3.c test2.c
test1.c
[struggleyb@cache duplite-delcare]$ ./test
t.ok in test2: 1000
t.ok in test1: 1000
t.ok in test3: 1000

At least, I define two copy of t, why there is no redefinition error?

Technically, I think that

struct test t;

constitutes a "tentative definition" of t. See 6.9.2. In order for it
to be an external definition, it would have to have an initializer. But
if you have one or more tentative definitions and no external
definition, the compiler acts as if there were a file scope declaration
initialized to zero (which would be an external definition).

So it does appear to have the effect of there being a definition,
initialized to zero, in each file (translation unit). 6.9 (5) would
appear to forbid this, unless I am misreading it.

It is forbidden but no diagnostic is required. If you do it anyway then
you invoke undefined behaviour which can range from the code being
accepted and doing what you expect through the code being rejected (I've
used implementations which would give an error on linking) to printing,
"you fancy Bob the Builder".
However, I know that it is commonly accepted by compilers: they will

So maybe it's technically an extension to the C language.

If it is documented then for that compiler it is accepted, if it isn't
then it is just chance if it works or fails. Whatever the case, don't do it!
 
N

Nate Eldredge

Flash Gordon said:
Nate Eldredge wrote, On 13/12/08 07:09:

[tentative definitions of an object in several translation units being
merged into one]
If it is documented then for that compiler it is accepted, if it isn't
then it is just chance if it works or fails. Whatever the case, don't do it!

Good to know.

FWIW, it appears the `-fno-common' flag to GCC will effectively disable
this extension, so that putting tentative definitions in multiple files
will result in an error at link time.
 

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

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top