假设我有用于建模各种数据包格式的结构:
#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可以解决这个问题,但是后来我失去了嵌套点缀引用的漂亮命名空间效果。
答案 0 :(得分:4)
对于即使在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的操作数的副作用“,因此明显的空指针顺序不应导致未定义的行为当不涉及可变长度数组时。
答案 1 :(得分:3)
使用C11或C99,创建一个虚拟复合文字并查找其大小。
printf("%zu\n", sizeof( ((Packet){ 0, { "" }}).format2 ));
输出
16
答案 2 :(得分:1)
您可以为这些嵌套的结构命名,不需要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;