views:

243

answers:

4

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_t) list1;
LINKED_LIST(foo_t) list2;

...

LINKED_LIST(foo_t) *pList = &list1;  /* Doesn't work */
A: 

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
A: 

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.

Simon
+6  A: 

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;
Helltone
No dispute that you can do what you suggest in your code example. However, the spec says "*If* one is declared with a tag...".
Oli Charlesworth
@Helltone: same remark as Oli, in exemple from OP the rule where structures are *not* declared with a tag should apply.
kriss
+2  A: 

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
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!
Oli Charlesworth
torak
@torak: 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
@torak: 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!
Oli Charlesworth