Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the effect of __attribute__ ((__packed__)) on nested structs?

Tags:

c++

c

gcc

g++

What is the effect of __attribute__ ((__packed__)) on nested structs? For example:

// C version
struct __attribute__ ((__packed__))
{
    struct
    {
        char c;
        int i;
    } bar;

    char c;
    int i;
} foo;

// C++ version
struct __attribute__ ((__packed__)) Foo
{
    struct Bar
    {
        char c;
        int i;
    } bar;

    char c;
    int i;
} foo;

I know foo will be tightly packed, but what about bar? Will it too be tightly packed? Does __attribute__ ((__packed__)) make the nested struct also packed?

like image 550
Cornstalks Avatar asked Jun 03 '13 19:06

Cornstalks


1 Answers

No, bar will not be tightly packed. It must be explicitly marked as __attribute__ ((__packed__)) if it is to be packed. Consider the following example:

#include <stdio.h>

struct
{
    struct
    {
        char c;
        int i;
    } bar;

    char c;
    int i;
} foo1;

struct __attribute__ ((__packed__))
{
    struct
    {
        char c;
        int i;
    } bar;

    char c;
    int i;
} foo2;

struct
{
    struct __attribute__ ((__packed__))
    {
        char c;
        int i;
    } bar;

    char c;
    int i;
} foo3;

struct __attribute__ ((__packed__))
{
    struct __attribute__ ((__packed__))
    {
        char c;
        int i;
    } bar;

    char c;
    int i;
} foo4;

int main()
{
    printf("sizeof(foo1): %d\n", (int)sizeof(foo1));
    printf("sizeof(foo2): %d\n", (int)sizeof(foo2));
    printf("sizeof(foo3): %d\n", (int)sizeof(foo3));
    printf("sizeof(foo4): %d\n", (int)sizeof(foo4));

    return 0;
}

The output of this program (compiling with gcc 4.2, 64-bits and clang 3.2, 64-bits) is:

sizeof(foo1): 16
sizeof(foo2): 13
sizeof(foo3): 12
sizeof(foo4): 10

If a struct and its nested structs are to all be tightly packed, __attribute__ ((__packed__)) must be explicitly declared for each struct. This makes sense, if you think of separating the nesting out so that bar's type is declared outside of foo, like so:

// Note Bar is not packed
struct Bar
{
    char c;
    int i;
};

struct __attribute__ ((__packed__))
{
    // Despite foo being packed, Bar is not, and thus bar will not be packed
    struct Bar bar;
    char c;
    int i;
} foo;

In the above example, for bar to be packed, Bar must be declared as __attribute__ ((__packed__)). If you were to copy 'n' paste these structures in order to nest them like in the first code example, you'll see that the packing behavior is consistent.


Corresponding C++ code (compiled with g++ 4.2 and clang++ 3.2, targeting 64-bits, which gives the exact same results as above):

#include <iostream>

struct Foo1
{
    struct Bar1
    {
        char c;
        int i;
    } bar;

    char c;
    int i;
} foo1;

struct __attribute__ ((__packed__)) Foo2
{
    struct Bar2
    {
        char c;
        int i;
    } bar;

    char c;
    int i;
} foo2;

struct Foo3
{
    struct __attribute__ ((__packed__)) Bar3
    {
        char c;
        int i;
    } bar;

    char c;
    int i;
} foo3;

struct __attribute__ ((__packed__)) Foo4
{
    struct __attribute__ ((__packed__)) Bar4
    {
        char c;
        int i;
    } bar;

    char c;
    int i;
} foo4;

int main()
{
    std::cout << "sizeof(foo1): " << (int)sizeof(foo1) << std::endl;
    std::cout << "sizeof(foo2): " << (int)sizeof(foo2) << std::endl;
    std::cout << "sizeof(foo3): " << (int)sizeof(foo3) << std::endl;
    std::cout << "sizeof(foo4): " << (int)sizeof(foo4) << std::endl;
}
like image 96
Cornstalks Avatar answered Oct 21 '22 15:10

Cornstalks