25

I have the following code:

int main(void)
{
    struct { int x; } a, b;
    struct { int x; } c;
    struct { int x; } *p;

    b = a;   /* OK */
    c = a;   /* Doesn't work */
    p = &a;  /* Doesn't work */

    return 0;
}

which fails to compile under GCC (3.4.6), with the following error:

test.c:8: error: incompatible types in assignment
test.c:9: warning: assignment from incompatible pointer type

Now, from what I understand (admittedly from the C99 standard), is that a and c should be compatible types, as they fulfill all the criteria in section 6.2.7, paragraph 1. I've tried compiling with std=c99, to no avail.

Presumably my interpretation of the standard is wrong?

Addendum

Incidentally, this question arises because I wanted to declare some template-like macros to wrap various datatypes without the overhead of having to declare named types/typedefs everywhere, e.g. a trivial example:

#define LINKED_LIST(T)   \
    struct {             \
        T    *pHead;     \
        T    *pTail;     \
    }

...

LINKED_LIST(foo) list1;
LINKED_LIST(foo) list2;

...

LINKED_LIST(foo) *pList = &list1;  /* Doesn't work */
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680

5 Answers5

10

struct { int x; } is a anonymous structure tag, two anonymous structures cannot have "the same name", which is a necessary condition for type compatibility. You can declare types that are compatible with a non-anonymous structure using typedef.

struct tmp { int x; }; // declare structure tag
typedef struct tmp type1;
typedef struct tmp type2; // declare 3 types compatible with struct tmp
typedef struct tmp type3; // and with each other

type1 a, b;
type2 c;
type3 *p;
b = a;
c = a;
p = &a;
Giovanni Funchal
  • 8,934
  • 13
  • 61
  • 110
  • 3
    No dispute that you can do what you suggest in your code example. However, the spec says "*If* one is declared with a tag...". – Oliver Charlesworth May 25 '10 at 14:41
  • 1
    same remark as Oli, in exemple from OP the rule where structures are *not* declared with a tag should apply. – kriss May 25 '10 at 15:31
10

Looking at the draft specification I'm guessing you're relying on the conditions that come after the statement:

Moreover, two structure, union, or enumerated types declared in separate translation units are compatible if their tags and members satisfy the following requirements ...

I think that the fact that these are all decared in the same C file means that they are in a single translation unit.

At a guess it would seem that this guarantees that when two C files include a header that declares a type then instances of that type will be compatible.

torak
  • 5,684
  • 21
  • 25
  • Interesting point. I was trying to think of an example that would test this theory under GCC, but couldn't think of one that exercises this idea. If one had e.g. void foo(struct {int x;}) in a header, attempting to do struct {int x;} a; ... foo(a); would fail, because that's all inside the same translation unit! – Oliver Charlesworth May 25 '10 at 14:46
  • @Oli Charlesworth: Yeah, not sure either. Have you considered casting to a "void *" in the assigment? I think that "LINKED_LIST(foo_t) *pList = (void *)&list1" might actually work. – torak May 25 '10 at 15:22
  • well, C99 does not say explicitely that is undefined behavior if two structures are declared in same translation unit. I read it as abusive intrepretation from gcc (I believe what C99 comitee wrote is synonymous with "even if declared in separate translation unit"... but obviously gcc implementors understood it otherwise). – kriss May 25 '10 at 15:36
  • 1
    Yes, and indeed that is my current solution to keep the compiler happy. I'm not entirely happy with it, because I'm not sure if I'm now inadvertently violating strict-aliasing rules! – Oliver Charlesworth May 25 '10 at 16:25
  • 3
    I'm pretty sure the standard intentionally restricts compatibility to cases where the definitions are in different translation units (where it does not affect the ability to use the assumption that pointers cannot alias each other for optimization). – R.. GitHub STOP HELPING ICE Feb 01 '11 at 02:13
  • 2
    As has been pointed out, 6.2.7p1 only applies to struct compatibility across translation units, not within the same file. In the same file, [6.7.2.3p5](http://port70.net/~nsz/c/c99/n1256.html#6.7.2.3p5) says *Each declaration of a structure, union, or enumerated type which does not include a tag declares a distinct type.* In addition [6.7.2.1p7](http://port70.net/~nsz/c/c99/n1256.html#6.7.2.1p7) says *The presence of a struct-declaration-list in a struct-or-union-specifier declares a new type, within a translation unit.* – jw013 Dec 11 '12 at 16:16
  • 2
    @Oli (continued) Both statements above support the idea that you can only define a struct once per translation unit. – jw013 Dec 11 '12 at 16:21
5

Compatibility of structures, unions, and enumerations

Within a single source file, each structure or union definition creates a new type that is neither the same as nor compatible with any other structure or union type. However, a type specifier that is a reference to a previously defined structure or union type is the same type. The tag associates the reference with the definition, and effectively acts as the type name. To illustrate this, only the types of structures j and k are compatible in this example:

struct   { int a; int b; } h;
struct   { int a; int b; } i;
struct S { int a; int b; } j;
struct S k;

Compatible structures may be assigned to each other.

Dirk
  • 3,030
  • 1
  • 34
  • 40
Yao Zhai
  • 121
  • 2
  • 7
2

Interestingly Clang gives the following:

error: incompatible type assigning 'struct <anonymous>', expected 'struct <anonymous>'

warning: incompatible pointer types assigning 'struct <anonymous> *', expected 'struct <anonymous> *'

It seems that if two (or more) anonymous structs are declared then the compiler does some internal magic which specifies which specific anonymous struct is being referred too.

Cromulent
  • 3,788
  • 4
  • 31
  • 41
-1

Considering paragraphs 6.2.7 (compatible types) and 6.5.16.1 (assignment rules), I understand the same as you.

It seems that with your code GCC behave like if your struct definitions where tagged with different tags (which is not the case). In wich case types wouldn't be compatible ones. However it still looks like a gcc bug.

Any feedback from other compilers that implements C99 standard ?

kriss
  • 23,497
  • 17
  • 97
  • 116
  • 1
    It's not a bug. You have 3 distinct anonymous structure types in the first code fragment in the question, and those three types are not compatible. – Jonathan Leffler Jun 23 '21 at 16:37