For purposes expressed in this question, we want to do this:
typedef struct { int a; } A;
typedef struct { struct { int a; }; int b; } B;
A *BToA(B *b) { return (A *) b; }
B *AToB(A *a) { return (B *) a; }
The desire is that the casts conform to C 2011 6.7.2.1 15, which says “A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa.”
Since the struct { int a; }
inside B
does not have a name, let’s call it A'
.
“Suitably” is not explicitly defined. I presume that if A *
is a valid pointer to an object of type A'
, then (A *) b
performs a suitable conversion, and, similarly, if a
is a pointer to an A'
that is in a B
, then (B *) a
is a suitable conversion.
So the question is: Is A *
a valid pointer to an object of type A'
?
Per 6.7.6.1, A *
is compatible with A' *
if A
is compatible with A'
.
Per 6.2.7, “Two types have compatible type if their types are the same… 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…”
These cannot be the same type by 6.7.2.3 5: “Each declaration of a structure, union, or enumerated type which does not include a tag declares a distinct type.”
Since they are not the same type, are they compatible? The text in 6.2.7 says they are compatible if declared in separate translation units, but these are in the same translation unit.
Depending on the type of structure, there are some things that we know about its compatibility. For example, we may know that a structure may not move at certain locations in certain directions (called reactions) or we may know that a beam or column is continuous, and so its slope cannot change abruptly.
After the typedef is complete, the type can then be referred to as either struct nodeor node, whichever you prefer. But if you don't give the structa tag, the type is anonymous until the typedef is complete, and cannot in any way be referred to before that.
Type compatibility is important during type conversions and operations. All valid declarations in the same scope that refer to the same object or function must have compatible types. Two types are compatible if they fit any of the following categories:
The general form of structure declaration is as follows − struct is the keyword. member1, member2 specifies the data items that makeup structure. There are three ways of declaring structure variables, which are as follows −
As you laid out in the question, the standard clearly and unambiguously says that two struct definitions struct { int a; }
in the same translation unit declare two incompatible types. Notwithstanding the fact that this might be "weird". Compilers have always followed the standard.
This seems like reasonable behaviour to me: if you happen to have semantically unrelated structs in your project that coincidentally have a member list with the same types, you do want the compiler to reject an accidental assignment between the two.
Re. the code in your question, according to 6.7.2.1/13,
The members of an anonymous structure or union are considered to be members of the containing structure or union.
So I would treat the definition of B
as being equivalent to:
typedef struct { int a; int b; } B;
for purposes of further analysis.
I haven't seen anything in the standard that says that both struct
are compatible and thus I would say that they are not.
The only thing that could get you a limited compatibility between the structures is the use of an union, as mentioned in 6.7.2.1§6:
One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them anywhere that a declaration of the completed type of the union is visible.
i.e., something like
typedef struct { int a; } A;
typedef struct { union { struct { int a; }; A export; }; int b; } B;
A *BToA(B *b) { return &b->export; }
B *AToB(A *a) { return (B *) a; }
should be safe, but for read accesses only: the standard did not really bother to specify what "inspecting" the common initial sequence means, but seems to use it in opposition to "modify".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With