C11 - convert pointer-to-struct to struct's anonymous first member

708 views Asked by At

The C standard states:

A pointer to a structure object, suitably cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa.

Is there any possible (and well-defined) way to perform such a "suitable cast" in C11 if the first member of the struct in question is an anonymous struct/union? Or to perform the "vice versa" backward cast if the containing struct is anonymous?

I guess that casting to a non-anonymous struct with the same member sequence as the anonymous struct would make this not well-defined as they are not compatible, and, therefore, not guaranteed to have the same memory layout.

However, the C standard states:

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 <...>

Can we try to apply this rule to anonymous structs? Say, if we have the following setup:

header.h:

struct container {
    struct {
        int a;
        char b;
    };
};

void print(struct container *pcontainer);

sep.c:

#include <stdio.h>
#include "header.h"

void print(struct container *pcontainer){
    printf("%d\n", ((struct { int a; char b; }*)pcontainer)->a);
}

main.c:

#include "header.h"

int main(void){
    struct container container, *pcontainer;

    pcontainer = &container;
    pcontainer->a = 1;

    print(pcontainer);

    return 0;
}

(this compiles on gcc (GCC) 4.8.3 20140911 and outputs 1).

Consider the anonymous struct used in the cast inside the print function and the anonymous struct that is the first member of the struct container that winds up in main.c. Could they be considered "types declared in separate translation units"? Also, do they really satisfy all the other compatibility requirements, or am I misunderstanding something?

1

There are 1 answers

8
2501 On

What is a translation unit:

5.1.1.1 Program Structure

  1. A C program need not all be translated at the same time. The text of the program is kept in units called source files, (or preprocessing files) in this International Standard. A source file together with all the headers and source files included via the preprocessing directive #include is known as a preprocessing translation unit. After preprocessing, a preprocessing translation unit is called a translation unit.

So the c file plus the headers after preprocessing form a single translation unit. Let's take the translation unit which is made out of sep.c and header.h. It contains two declarations of the struct struct { int a; char b; }, one in the struct container and the other in the function print. Those structs are declared in the same translation unit.

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...

the remaining text is referring to types declared in separate translation units.

Since the structs are not declared in separate translation units, they do not fall under the 6.2.7 rule.

Therefore in my interpretation the structs, the one in struct container and the other in the cast in the print(), aren't compatible.