【问题标题】:sizeof anonymous nested structsizeof 匿名嵌套结构
【发布时间】:2023-03-19 02:54:01
【问题描述】:

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

#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;

我可以预期sizeof(Packet) 将是21。但是有没有办法做类似的事情:

sizeof(Packet.format2)

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

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

aPacketPointer->format2.value1; // not so onerous, but if the nesting gets deeper...

那么有时这样做会很好:

Packet.format2 *formatPtr = &aPacketPointer->format2;
formatPtr->value2; // etc

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

【问题讨论】:

  • 您可能认为sizeof(Packet) 将是 21,但在我尝试过的至少两个编译器配置上,它的结果为 32。也许这对您的使用不会有问题,因为至少它比您预期的要大(另一方面,也许这是一个问题)。其他可能让您感到惊讶的是,包含bytesformatformat2union 的偏移量为8 - 编译器在packetLength 字段和联合之间放置了填充。在 C/C++ 结构中建模在线数据对象时需要非常小心。
  • 请记住,@MichaelBurr 可能正在使用 32b 架构进行测试,默认情况下所有内容都会被填充。 8b 处理器编译器不进行填充。反正我也没见过。
  • 是的。为了通过有线协议将字节转换为结构,从一个基本假设开始,即您可以强制并信任您的结构布局。不同的编译器通常有不同的机制来执行此操作。

标签: c gcc struct nested


【解决方案1】:

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

#define sizeof_field(s,m) (sizeof((((s*)0)->m)))

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

当我这样使用它时:

std::cout << sizeof_field(Packet,format1) << std::endl;
std::cout << sizeof_field(Packet,format2) << std::endl;

我得到了输出:

6
16

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

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

...
typeof_field(Packet,format2)* f2 = &foo.format2;

说实话,我觉得这个结构很丑,但它可能仍然比你可用的其他选项更好。

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

【讨论】:

  • 注意:在这种情况下,允许在 sizeof 内取消引用空指针,因为 sizeof 的操作数未计算(因为这不是 VLA)。 (对于用户定义的 offsetof 克隆就不能这么说了)
【解决方案2】:

使用 C11 或 C99,创建一个虚拟复合文字并查找其大小。

printf("%zu\n", sizeof(   ((Packet){ 0, { "" }}).format2   ));

输出

16

【讨论】:

    【解决方案3】:

    你可以给这些嵌套结构一个名字,不需要 typedef。像这样:

    typedef struct {
        u8 packetLength;
        union {
            u8 bytes[MaxPacket];
            struct myformat1 {
                u16 field1;
                u16 field2;
                u16 field3;
            } format1;
            struct myformat2 {
                double value1;
                double value2;
            } format2;
        };
    } Packet;
    

    然后你可以写例如sizeof(struct myformat1),声明该类型的变量等

    你也可以在之后添加一个 typedef,例如

    typedef struct myformat1 myformat1;
    

    【讨论】:

      猜你喜欢
      • 2018-01-27
      • 1970-01-01
      • 2018-02-01
      • 1970-01-01
      • 2012-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多