The GNU Compiler Collection (GCC) provides several language features not found in ISO standard C.
As I write this article, GCC has more than 60 different extensions that change the behavior or add functionality to the C language (and also C++). Some of these extensions are very interesting, others are a little bit confusing and a few somewhat dangerous!
It is important to know these GCC extensions because many of them are used by several free and open source projects, including the Linux kernel.
Let’s take a look at some of them?
Nested functions
GCC allows the declaration of nested functions (a function defined inside another function).
The nested function’s name will be local to the block where it is defined and can access all the variables of the containing function that are visible at the point of its definition.
|
|
$ gcc nested.c -Wall -Werror -o nested
$ ./nested
Inside nested function!
The typeof keyword
We can use the typeof keyword to refer to the type of an expression, making it possible to do generic programming in C!
For example, the max(a,b) macro below operates on any arithmetic type:
|
|
$ gcc typeof.c -Wall -Werror -o typeof
$ ./typeof
char max is 20
int max is 4096
float max is 2.000000
Empty structures
GCC allows a C structure to have no members (the structure will have size zero).
|
|
$ gcc empty.c -Wall -Werror -o empty
$ ./empty
sizeof struct empty is 0
In C++, empty structures are part of the language.
Case ranges
In GCC, we can specify a range of consecutive values in a single case label in the format “case start … end”. Crazy, right?
This has the same effect as the proper number of individual case labels, one for each integer value from start to end, inclusive.
|
|
$ gcc ranges.c -Wall -Werror -o ranges
$ ./ranges
[a] is a lowercase letter.
Zero-length arrays
GCC allows the declaration of zero-length arrays.
A zero-length array can be useful as the last element of a structure that is, for example, a header for a variable-length object. In this case, the name of the zero-length array can be used as a pointer to the dynamically allocated object.
|
|
$ gcc array.c -Wall -Werror -o array
$ ./array
msg header is at 0x55c428265260
msg content is at 0x55c428265268
There are many more extensions but, should we really use them?
Should we use GCC extensions?
All of the examples were compiled with GCC 7.4.0.
The extensions are available without any extra compiler flag because by default GCC 7.4 compiles with -std=gnu11, which means support for the ISO C11 standard plus GCC extensions.
Although some of these extensions are quite useful, the tradeoff is portability. Using the GCC extensions, we could have problems building the program with another compiler.
For example, Clang has its own set of extensions and does not support all of GCC extensions, like nested functions.
$ clang nested.c -o nested
nested.c:5:19: error: function definition is not allowed here
void p (void) { printf("Inside a nested function!\n"); }
^
nested.c:7:5: warning: implicit declaration of function 'p' is invalid in C99 [-Wimplicit-function-declaration]
p();
^
1 warning and 1 error generated.
If you want to find out if you are using any GCC extension, enable the -pedantic compiler option to generate warnings or the -pedantic-errors compiler option to generate errors.
$ gcc arrayzero.c -o arrayzero -pedantic-errors
arrayzero.c:7:7: error: ISO C forbids zero-size array ‘content’ [-Wpedantic]
char content[0];
^~~~~~~
And if you want to use GCC extensions and still keep the program portable, you can test for the availability of these features doing conditional compilation with the macro __GNUC__, which is always defined under GCC.
The complete list of GCC extensions to the C language is available in the GCC documentation.
What about a challenge now? Can you find two GCC extensions used in the program below, just by reading the source code?
|
|
So if you are using GCC in any software you are maintaining, why don’t you try to compile with -pedantic or -pedantic-errors to find out if you are using (by design or mistake) any GCC extension? You may be surprised with the result! ;-)
About the author: Sergio Prado has been working with embedded systems for more than 25 years. If you want to know more about his work, please visit the About Me page or Embedded Labworks website.
Please email your comments or questions to hello at sergioprado.blog, or sign up the newsletter to receive updates.