匿名嵌套结构的大小

Tra*_*ggs 4 c gcc struct nested

假设我有用于模拟各种数据包格式的结构:

#define MaxPacket 20

typedef struct {
    u8 packetLength;
    union {
        u8 bytes[MaxPacket];
        struct {
            u16 field1;
            u16 field2;
            u16 field3;
        } format1;
        struct {
            double value1;
            double value2;
        } format2;
    };
} Packet;
Run Code Online (Sandbox Code Playgroud)

我可以预期那sizeof(Packet)将是21。但是有什么办法可以做这样的事情:

sizeof(Packet.format2)
Run Code Online (Sandbox Code Playgroud)

? 我试过了,但编译器不满意。显然,我可以将其format1作为单独的 typedef 取出,然后我可以sizeof(format1). 但我很好奇我是否必须经历这一切。我喜欢格式的层次结构。这是在 8 位处理器上使用 gcc。

如果有办法使用嵌套类型,我同样感兴趣。如果我必须做很多

aPacketPointer->format2.value1; // not so onerous, but if the nesting gets deeper...
Run Code Online (Sandbox Code Playgroud)

那么有时这样做会很好:

Packet.format2 *formatPtr = &aPacketPointer->format2;
formatPtr->value2; // etc
Run Code Online (Sandbox Code Playgroud)

同样,重构为一堆前面的 typedef 可以解决这个问题,但是我失去了嵌套点引用的良好命名空间效果。

Mic*_*urr 5

对于即使在 C90 中也能工作的东西,您可以使用以您的工具链的offsetof()宏为模型的宏:

#define sizeof_field(s,m) (sizeof((((s*)0)->m)))
Run Code Online (Sandbox Code Playgroud)

如果您的工具链的offsetof()宏不是基于转换0为指向结构类型的指针,则相应地调整它。

当我像这样使用它时:

std::cout << sizeof_field(Packet,format1) << std::endl;
std::cout << sizeof_field(Packet,format2) << std::endl;
Run Code Online (Sandbox Code Playgroud)

我得到输出:

6
16
Run Code Online (Sandbox Code Playgroud)

对于您的第二个问题,如果您愿意依赖 GCC 的typeof扩展,您可以创建一个类似的宏来声明指向嵌套匿名结构的指针:

#define typeof_field(s,m) typeof(((s*)0)->m)

...
typeof_field(Packet,format2)* f2 = &foo.format2;
Run Code Online (Sandbox Code Playgroud)

老实说,我发现这种构造非常丑陋,但它可能仍然比您可用的其他选项更好。

GCC 记录了“当且仅当它是可变修改类型的表达式或此类类型的名称时,才会评估 typeof 的操作数的副作用”,因此当变量为变量时,明显的空指针引用不应导致未定义的行为不涉及长度数组。

  • 注意:在这种情况下,可以在 sizeof 内部取消引用空指针,因为 sizeof 的操作数没有被评估(因为这不是 VLA)。(对于用户定义的 offsetof clones 则不能这样说) (2认同)