Why do these C struct definitions give warnings and errors?

12,836

Solution 1

typedef struct __attribute__((packed)) {
    int a;
} bar;

vs

typedef struct {
    int a;
} baz __attribute__((packed));

In the first you said "consider this anonymous structure, with the attribute packed, that has a member a. then create an alias for this structure, and name that 'bar'". The normal syntax for describing a struct without doing it anonymously and having to typedef it is

struct bar { int a; };

in the second declaration you said "consider this anonymous structure, that has a member a. then create an alias for this structure, and name that 'baz who is packed'".

It doesn't work because you're trying to apply the attribute to the alias in a typedef, not to the structure definition.

typedef <entity> <alias>;

I would advise putting on a hit on whomever suggested you use the "typedef" syntax for describing structs :)

Solution 2

The reason that it works in the first two instances is because __attribute__((packed)) can only be applied to a struct, union or enum. In the first example, you're declaring a struct called foo, in the second you are declaring a struct called bar. In this second example, typedef converts a declaration of a variable into a declaration of a type.

Your third example is declaring a variable called baz and trying to declare it as packed. Since packing info is attached to the type, not an instance, this makes no sense, and the compiler ignores it.

Here are details on how attributes work in gcc.

You really shouldn't be even using packed unless you know exactly what you are doing. For one thing, __attribute__ is not standard C. If is a gcc extension and so won't work with any other compiler.

For another, there are very few situations where it is actually needed. In your code above, for instance, it is a no-op even in the first two instances as packing removes space between members, and you've only got one member in each struct. The reason that packing structures isn't the default is because common datatypes just work better when aligned on a certain boundary. For instance, access to an int will perform better if aligned on a memory location that is a multiple of four. See the wiki entry on data structure alignment for more information.

Solution 3

The keyword __attribute__((packed)) applies to struct.

In

typedef struct {
    int a;
} baz __attribute__((packed));

typedef associates baz with the struct - the attributes comes after, and applies to nothing - gcc ignores it. To fix this, allow typedef to associate the whole struct declaration, including the attribute, by placing baz after the attribute:

typedef struct {
    int a;
} __attribute__((packed)) baz;

In the 2nd example, the struct declaration is wrong

struct qux __attribute__((packed)) {
    int a;
} 

as quz should appear after the attribute:

struct __attribute__((packed)) qux {
    int a;
} 

It is usually better to let the compiler optimizes the structure and align the inner elements in memory in a way the CPU processes them more efficiently.

Packing a structure, however, may be important at times when building a data structure that has to be packed, in order to cope, for instance, with a driver demands.

Share:
12,836
gsgx
Author by

gsgx

I'm currently studying computer science at the University of Michigan. I enjoy working on operating systems and compilers, developing Android applications, and hacking on the Android Open Source Project.

Updated on June 05, 2022

Comments

  • gsgx
    gsgx almost 2 years

    Why do these two struct definitions compile fine:

    struct foo {
        int a;
    } __attribute__((packed));
    
    typedef struct __attribute__((packed)) {
        int a;
    } bar;
    

    While this one gives a warning:

    typedef struct {
        int a;
    } baz __attribute__((packed));
    
    
    warning: ‘packed’ attribute ignored [-Wattributes]
    

    And this one gives an error and a warning:

    typedef struct qux __attribute__((packed)) {
        int a;
    } qux;
    
    error: expected identifier or ‘(’ before ‘{’ token
    warning: data definition has no type or storage class [enabled by default]
    

    As a novice C programmer, the fact that the last two definitions don't work seems like a fairly arbitrary choice on the parts of the language designers/compiler writers. Is there a reason for this? I'm using gcc 4.7.3.