Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C - Incompatible Pointer Type

Why does the following code give warnings?

int main(void)
{
    struct {int x; int y;} test = {42, 1337};
    struct {int x; int y;} *test_ptr = &test;
}

Results:

warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
         struct {int x; int y;} *test_ptr = &test;
                                            ^
like image 750
Erik W Avatar asked Jul 11 '16 03:07

Erik W


2 Answers

They're two anonymous structure types (they neither have a tag). All such structure types (in a single translation unit) are distinct — they're never the same type. Add a tag!

The relevant sentence in the standard is in §6.7.2.1 Structure and union specifiers:

¶8 The presence of a struct-declaration-list in a struct-or-union-specifier declares a new type, within a translation unit.

The struct-declaration-list refers to the material between { and } in the type.

That means that in your code, there are two separate types, one for each struct { … }. The two types are separate; you cannot officially assign a value of one type to the other, nor create pointers, etc. In fact, you can't reference those types again after the semicolon.

That means you could have:

int main(void)
{
    struct {int x; int y;} test = {42, 1337}, *tp = &test;
    struct {int x; int y;} result, *result_ptr;
    result_ptr = &result;
    …
}

Now test and tp refer to the same type (one a structure, one a pointer to the structure), and similarly result and result_ptr refer to the same type, and the initializations and assignments are fine, but the two types are different. It's not clear that you create a compound literal of either type — you'd have to write (struct {int x; int y;}){.y = 9, .x = 8}, but the presence of the struct-declaration-list means that is another new type.

As noted in the comments, there is also section §6.2.7 Compatible type and composite type, which says:

¶1 … Moreover, two structure, union, or enumerated types declared in separate translation units are compatible if their tags and members satisfy the following requirements: If one is declared with a tag, the other shall be declared with the same tag. If both are completed anywhere within their respective translation units, then the following additional requirements apply: there shall be a one-to-one correspondence between their members such that each pair of corresponding members are declared with compatible types; if one member of the pair is declared with an alignment specifier, the other is declared with an equivalent alignment specifier; and if one member of the pair is declared with a name, the other is declared with the same name. For two structures, corresponding members shall be declared in the same order. For two structures or unions, corresponding bit-fields shall have the same widths.

Roughly speaking, that says that if the definitions of the types in the two translation units (think 'source files' plus included headers) are the same, then they refer to the same type. Thank goodness for that! Otherwise, you couldn't have the standard I/O library working, amongst other minor details.

like image 73
Jonathan Leffler Avatar answered Nov 19 '22 08:11

Jonathan Leffler


Variables &test and test_ptr, which are anonymous structs, have different types.

Anonymous structs defined in the same translation unit are never compatible types1 as the Standard doesn't define compatibility for two structure type definitions in the same translation unit.

To have your code compile, you could do:

struct {int x; int y;} test = {42, 1337} , *test_ptr;
test_ptr = &test;

1 (Quoted from: ISO:IEC 9899:201X 6.2.7 Compatible type and composite type 1)
Two types have compatible type if their types are the same. Additional rules for determining whether two types are compatible are described in 6.7.2 for type specifiers, in 6.7.3 for type qualifiers, and in 6.7.6 for declarators. Moreover, two structure, union, or enumerated types declared in separate translation units are compatible if their tags and members satisfy the following requirements: If one is declared with a tag, the other shall be declared with the same tag. If both are completed anywhere within their respective translation units, then the following additional requirements apply: there shall be a one-to-one correspondence between their members such that each pair of corresponding members are declared with compatible types; if one member of the pair is declared with an alignment specifier, the other is declared with an equivalent alignment specifier; and if one member of the pair is declared with a name, the other is declared with the same name. For two structures, corresponding members shall be declared in the same order. For two structures or unions, corresponding bit-fields shall have the same widths. For two enumerations, corresponding members shall have the same values.

like image 13
2501 Avatar answered Nov 19 '22 08:11

2501