Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sizeof anonymous nested struct

Tags:

c

gcc

struct

nested

Suppose I have structure I'm using to model various packet formats:

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

I can expect that sizeof(Packet) will be 21. But is there any way to do something like:

sizeof(Packet.format2)

? I've tried that, but the compiler is not happy. Obviously, I could pull the format1 out as a separate typedef and then I could sizeof(format1). But I'm curious if I have to through all of that. I like the hierarchical composition of the formats. This is with gcc on an 8bit processor.

I'm equally interested if there's a way to use the nested type. IF I have to do a lot of

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

Then sometimes it would be nice to do:

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

Again, refactoring into a bunch of preceding typedefs would solve this problem, but then I lose the nice namespacing effect of the nested dotted references.

like image 921
Travis Griggs Avatar asked Jan 06 '23 16:01

Travis Griggs


2 Answers

For something that will work even in C90, you can use a macro modeled on your toolchain's offsetof() macro:

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

Adjust it accordingly if your toolchain's offsetof() macro isn't based on casting 0 to a pointer to the structure's type.

When I use it like so:

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

I get the output:

6
16

For your second question, if you're willing to rely on GCC's typeof extension you can create a similar macro for declaring pointers to your nested anonymous structs:

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

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

To be honest, I find that construct pretty ugly, but it might still be better than other options you have available.

GCC documents that the "operand of typeof is evaluated for its side effects if and only if it is an expression of variably modified type or the name of such a type", so the apparent null pointer deference should not result in undefined behavior when a variable length array is not involved.

like image 122
Michael Burr Avatar answered Jan 09 '23 07:01

Michael Burr


Using C11 or C99, create a dummy compound literal and seek its size.

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

Output

16
like image 24
chux - Reinstate Monica Avatar answered Jan 09 '23 07:01

chux - Reinstate Monica