C11, 6.2.7 Compatible type and composite type, 1:
Moreover, two structure, union, or enumerated types declared in separate translation units are compatible if their tags and members satisfy the following requirements: ...
Here we see the requirements for structure types declared in separate translation units. What are the requirements for the structure types declared in the same translation unit?
Extra: C 17 standard (N4713) says:
For example, otherwise-identical struct types with different tag names are “compatible” in C but are distinctly different types in C .
A quick test:
struct x { int x; } x;
struct y { int x; } *p = &x;
$ gcc t0.c -std=c11 -pedantic -Wall -Wextra
warning: initialization of 'struct y *' from incompatible pointer type 'struct x *' [-Wincompatible-pointer-types]
$ clang t0.c -std=c11 -pedantic -Wall -Wextra
warning: incompatible pointer types initializing 'struct y *' with an expression of type 'struct x *' [-Wincompatible-pointer-types]
$ icc t0.c -std=c11 -pedantic -Wall -Wextra
warning #144: a value of type "struct x *" cannot be used to initialize an entity of type "struct y *"
$ cl t0.c /std:c11
warning C4133: 'initializing': incompatible types - from 'x *' to 'y *'
Here we see that otherwise-identical struct types with different tag names declared in the same translation unit are not compatible.
UPD. Here is a relevant question about compatible struct types (which turned out to be not compatible) in separate translation units.
UPD. To user @dbush. Re: "linker determines that they are compatible". Here is the code:
$ cat foo.c
struct struc1 {
int x;
};
int foo(struct struc1 *s)
{
return s->x;
}
$ cat main.c
struct struc {
float x;
};
int foo(struct struc *s);
int main(void)
{
return foo(&(struct struc){1.2f});
}
$ gcc foo.c main.c -std=c11 -pedantic -Wall -Wextra
<nothing>
Why linker does not complain here?
CodePudding user response:
Simply, two structs in the same translation unit are not compatible.
The rule regarding compatible struct types in different translation units exists because there's no direct link between a struct declared in one translation unit and an identical struct declared in another. This is true even if the two translation units took their declarations from the same source file.
For example:
h1.h:
struct x {
int i;
char *s;
};
f1.c:
#include "h1.h"
void foo1(struct x *s)
{
s->i;
}
f1.c:
#include "h1.h"
void foo2(struct x *s)
{
--s->i;
}
Here, struct x
is declared separately in the f1.c translation unit and in the f2.c translation unit. The fact that both included the same header file with that declaration doesn't matter.
When the linker links these two translation units, it sees the declaration in each unit and determines that they are compatible.
Also, note that the text in the C standard has "compatible" in quotes suggesting they aren't really compatible.
CodePudding user response:
Notice one of the requirements for struct or union types to be compatible is
If one is declared with a tag, the other shall be declared with the same tag.
That is, if the first type is called struct S
, then the second type is also called struct S
. (So your struct x
and struct y
are not compatible whether they're in the same TU or different ones.) But if these are used in the same translation unit, they're actually the same type! And a type is always compatible with itself.
Anonymous types as in struct { int x; int y; } point;
are a little trickier. Without either a tag or a typedef name, there's no way to reuse the same type in the same TU. Another struct
body with the same members is a different type. However, if one TU has struct { int x; int y; } point = {2,1};
and another has extern struct { int x; int y; };
, we do need the types in the two TUs for the same variable to be compatible.
CodePudding user response:
What are the requirements for compatible structure types declared in the same translation unit?
The requirement is:
Two types have compatible type if their types are the same.
We know that:
The presence of a struct-declaration-list in a struct-or-union-specifier declares a new type, within a translation unit.
The struct x { int x; }
declares a type, then struct y { int x; }
declares another new type. These types are not the same.
The text:
otherwise-identical struct types with different tag names are “compatible” in C
Could be about the compatibility with ANSI C. In ANSI C two structures with different tags in different translation units are compatible.