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 a very big fan of max warnings anyway).
There are two flavors:
The (m) is the number of the "format string" parameter, and (n) is the number of the first variadic parameter. To see some examples:
With the functions so declared, the compiler will examine the argument lists/* 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 */
Note that the "standard" library functions - printf and the like - are already understood by the compiler by default.$ cat test.c 1 extern void eprintf(const char *format, ...) 2 __attribute__((format(printf, 1, 2))); 3 4 void foo() 5 { 6 eprintf("s=%s\n", 5); /* error on this line */ 7 8 eprintf("n=%d,%d,%d\n", 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
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:
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.extern void exit(int) __attribute__((noreturn)); extern void abort(void) __attribute__((noreturn));
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.
But when we add __attribute__, the compiler suppresses the spurious warning:$ 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
$ 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!
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:
By adding __attribute__((const)), the compiler can choose to call the function just once and cache the return value.extern int square(int n) __attribute__((const)); ... for (i = 0; i < 100; i++ ) { total += square(5) + i; }
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 the also 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.
If this is tucked away safely in a library header file, all programs that call this function receive this checking./* 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)));
Note that __attribute__ applies to function declarations, not definitions, and we're not sure why this is. So when defining a function that that merits this treatment, an extra declaration must be used (in the same file):/* If we're not using GNU C, elide __attribute__ */ #ifndef __GNUC__ # define __attribute__(x) /*NOTHING*/ #endif
/* function declaration */ void die(const char *format, ...) __attribute__((noreturn)) __attribute__((format(printf,1,2))); void die(const char *format, ...) { /* function definition */ }