Gcc attribute error

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: t...

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.

Jens Gustedt's user avatar

Jens Gustedt

76k6 gold badges101 silver badges175 bronze badges

asked Jun 2, 2013 at 3:15

gsgx's user avatar

3

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 :)

answered Jun 2, 2013 at 4:58

kfsone's user avatar

kfsonekfsone

23.3k2 gold badges40 silver badges71 bronze badges

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.

answered Jun 2, 2013 at 3:55

Gort the Robot's user avatar

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.

answered Jun 2, 2013 at 3:55

Déjà vu's user avatar

Déjà vuDéjà vu

27.9k5 gold badges72 silver badges100 bronze badges

This is a rather odd question because it’s all very well explained in the manual. However to there isn’t anything arbitrary about it, you’re just not exploring the complete use of this built-in keyword:

__attribute__(()) is a general purpose gcc extension. There are function attributes, type attributes and variable attributes.

Where you place the word __attribute__ determines what it applies to. You could potentially have several __attribute__s in a given declaration so it’s not arbitrary to make some of it syntactically unacceptable for easier internal parsing.

answered Jun 2, 2013 at 4:02

Ahmed Masud's user avatar

Ahmed MasudAhmed Masud

21.1k3 gold badges34 silver badges57 bronze badges

One of the best (but little known) features of GNU C is the
__attribute__ mechanism, which allows a developer to attach
characteristics to function declarations to allow the
compiler to perform more error checking. It was designed in a way to
be compatible with non-GNU implementations, and we’ve been using this
for years in highly portable code with very good results.

Note that __attribute__ spelled with two underscores before and
two after, and there are always two sets of parentheses surrounding
the contents. There is a good reason for this — see below. Gnu CC needs
to use the -Wall compiler directive to enable this (yes, there is
a finer degree of warnings control available, but we are very big fans
of max warnings anyway).

__attribute__ unused

One of the easiest attributes to use, this marks a variable as intentionally being
possibly unused. Not only does this quiet the compiler from issuing an unused-variable
warning, it tells the human the same thing: this is intentional.

Of course, it’s a good idea to actually remove variables that you’re not using, this
is not always possible. A common case of the unused int argc parameter to
main() is one, as are variables sometimes excluded by conditional compilation.

int main(int argc, char **argv)
{
   /* code that uses argv, but not argc */
}

$ gcc -W test.c
test.c:1: warning: unused parameter 'argc'

The __attribute__ is added just after the variable name, and though it can
appear unwieldy, it’s a style you can get used to:

int main(int argc __attribute__((unused)), char **argv)
{ ...

Additional uses shown, each with a comment showing the compiler warning
it might have generated. Here we assume the code is being compiled without
the DEBUG macro being defined, which excludes the actual use of mypid.

/* warning: 'someFunction' declared 'static' but never defined */
static int someFunction() __attribute__((unused));

int main(int argc __attribute__((unused)), char **argv)
{
/* warning: unused variable 'mypid' */
int	mypid __attribute__((unused)) = getpid();

#ifdef DEBUG
	printf("My PID = %dn", mypid);
#endif

	return 0;
}

__attribute__ format

This __attribute__ allows assigning printf-like or scanf-like
characteristics to the declared function, and this enables the compiler
to check the format string against the parameters provided throughout
the code. This is exceptionally helpful in tracking down hard-to-find
bugs.

There are two flavors:

  • __attribute__((format(printf,m,n)))
  • __attribute__((format(scanf,m,n)))

but in practice we use the first one much more often.

The (m) is the number of the «format string» parameter, and
(n) is the number of the first variadic parameter. To see some
examples:

/* like printf() but to standard error only */
extern void eprintf(const char *format, ...)
	__attribute__((format(printf, 1, 2)));  /* 1=format 2=params */

/* printf only if debugging is at the desired level */
extern void dprintf(int dlevel, const char *format, ...)
	__attribute__((format(printf, 2, 3)));  /* 2=format 3=params */

With the functions so declared, the compiler will examine the
argument lists

$ cat test.c
1  extern void eprintf(const char *format, ...)
2               __attribute__((format(printf, 1, 2)));
3
4  void foo()
5  {
6      eprintf("s=%sn", 5);             /* error on this line */
7
8      eprintf("n=%d,%d,%dn", 1, 2);    /* error on this line */
9  }

$ cc -Wall -c test.c
test.c: In function `foo':
test.c:6: warning: format argument is not a pointer (arg 2)
test.c:8: warning: too few arguments for format

Note that the «standard» library functions — printf and the like
— are already understood by the compiler by default.

__attribute__ noreturn

This attribute tells the compiler that the function won’t ever return,
and this can be used to suppress errors about code paths not being
reached. The C library functions abort() and exit() are both
declared with this attribute:

extern void exit(int)   __attribute__((noreturn));
extern void abort(void) __attribute__((noreturn));

Once tagged this way, the compiler can keep track of paths through
the code and suppress errors that won’t ever happen due to the flow
of control never returning after the function call.

In this example, two nearly-identical C source files refer to an
«exitnow()» function that never returns, but without the
__attribute__ tag, the compiler issues a warning. The compiler
is correct here, because it has no way of knowing that control
doesn’t return.

$ cat test1.c
extern void exitnow();

int foo(int n)
{
        if ( n > 0 )
	{
                exitnow();
		/* control never reaches this point */
	}
        else
                return 0;
}

$ cc -c -Wall test1.c
test1.c: In function `foo':
test1.c:9: warning: this function may return with or without a value

But when we add __attribute__, the compiler suppresses the spurious
warning:

$ cat test2.c
extern void exitnow() __attribute__((noreturn));

int foo(int n)
{
        if ( n > 0 )
                exitnow();
        else
                return 0;
}

$ cc -c -Wall test2.c
no warnings!

__attribute__ const

This attribute marks the function as considering only its numeric parameters.
This is mainly intended for the
compiler to optimize away repeated calls to a function that the compiler
knows will return the same value repeatedly. It applies mostly to math
functions that have no static state or side effects, and whose return
is solely determined by the inputs.

In this highly-contrived example, the compiler normally must call
the square() function in every loop even though we know that it’s
going to return the same value each time:

extern int square(int n) __attribute__((const));

...
	for (i = 0; i < 100; i++ )
	{
		total += square(5) + i;
	}

By adding __attribute__((const)), the compiler can choose
to call the function just once and cache the return value.

In virtually every case, const can’t be used on functions that
take pointers, because the function is not considering just the
function parameters but also the data the parameters point to,
and it will almost certainly break the code very badly in ways
that will be nearly impossible to track down.

Furthermore, the functions so tagged cannot have any side effects
or static state, so things like getchar() or time() would
behave very poorly under these circumstances.

Putting them together

Multiple __attributes__ can be strung together on a single
declaration, and this is not uncommon in practice. You can either use
two separate __attribute__s, or use one with a comma-separated list:

/* send printf-like message to stderr and exit */
extern void die(const char *format, ...)
	__attribute__((noreturn))
	__attribute__((format(printf, 1, 2)));

/*or*/

extern void die(const char *format, ...)
	__attribute__((noreturn, format(printf, 1, 2)));

If this is tucked away safely in a library header file, all programs
that call this function receive this checking.

Compatibility with non-GNU compilers

Fortunately, the __attribute__ mechanism was cleverly designed in a way
to make it easy to quietly eliminate them if used on platforms other than
GNU C. Superficially, __attribute__ appears to have multiple parameters
(which would typically rule out using a macro), but the two sets of
parentheses effectively make it a single parameter, and in practice this
works very nicely.

/* If we're not using GNU C, elide __attribute__ */
#ifndef __GNUC__
#  define  __attribute__(x)  /*NOTHING*/
#endif

Note that __attribute__ applies to function declarations, not
definitions, and we’re not sure why this is. So when defining
a function that merits this treatment, an extra declaration
must be used (in the same file):

/* function declaration */
void die(const char *format, ...) __attribute__((noreturn))
                                  __attribute__((format(printf,1,2)));

void die(const char *format, ...)
{
	/* function definition */
}

Other References

We’ll note that there are many more attributes available, including
those for variables and types, and they are not covered here:
we have chosen to just touch on the high points.
Those wishing more information can
find it in the GNU online documentation at
http://gcc.gnu.org:

GCC 4.0

GCC 4.0 Function Attributes

GCC 4.0 Variable Attributes

GCC 4.0 Type Attributes

GCC 3.2

GCC 3.2 Function Attributes

GCC 3.2 Variable Attributes

GCC 3.2 Type Attributes

GCC 3.1

GCC 3.1 Function Attributes

GCC 3.1 Variable Attributes

GCC 3.1 Type Attributes

GCC 3.0.4

Function Attributes

Variable Attributes

Type Attributes

GCC 2.95.3

Function Attributes

Variable Attributes

Type Attributes

Description:

     The `format' attribute specifies that a function takes `printf',
     `scanf', `strftime' or `strfmon' style arguments which should be
     type-checked against a format string.  For example, the
     declaration:

          extern int
          my_printf (void *my_object, const char *my_format, ...)
                __attribute__ ((format (printf, 2, 3)));

     causes the compiler to check the arguments in calls to `my_printf'
     for consistency with the `printf' style format string argument
     `my_format'.

     The parameter ARCHETYPE determines how the format string is
     interpreted, and should be `printf', `scanf', `strftime' or
     `strfmon'.  (You can also use `__printf__', `__scanf__',
     `__strftime__' or `__strfmon__'.)  The parameter STRING-INDEX
     specifies which argument is the format string argument (starting
     from 1), while FIRST-TO-CHECK is the number of the first argument
     to check against the format string.  For functions where the
     arguments are not available to be checked (such as `vprintf'),
     specify the third parameter as zero.  In this case the compiler
     only checks the format string for consistency.  For `strftime'
     formats, the third parameter is required to be zero.  Since
     non-static C++ methods have an implicit `this' argument, the
     arguments of such methods should be counted from two, not one, when
     giving values for STRING-INDEX and FIRST-TO-CHECK.

     In the example above, the format string (`my_format') is the second
     argument of the function `my_print', and the arguments to check
     start with the third argument, so the correct parameters for the
     format attribute are 2 and 3.

     The `format' attribute allows you to identify your own functions
     which take format strings as arguments, so that GCC can check the
     calls to these functions for errors.  The compiler always (unless
     `-ffreestanding' is used) checks formats for the standard library
     functions `printf', `fprintf', `sprintf', `scanf', `fscanf',
     `sscanf', `strftime', `vprintf', `vfprintf' and `vsprintf'
     whenever such warnings are requested (using `-Wformat'), so there
     is no need to modify the header file `stdio.h'.  In C99 mode, the
     functions `snprintf', `vsnprintf', `vscanf', `vfscanf' and
     `vsscanf' are also checked.  Except in strictly conforming C
     standard modes, the X/Open function `strfmon' is also checked as
     are `printf_unlocked' and `fprintf_unlocked'.  *Note Options
     Controlling C Dialect: C Dialect Options.

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Gbic security crypt 4 vn data crc error
  • Gbic invalid error detected on gi0 1 putting gi0 1 in err disable state
  • Gbak error size specification either missing or incorrect for file
  • Gbak error requires both input and output filenames
  • Gbak error gds receive failed

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии