The Best GCC Tips and Tricks You Must Know

The Hitchhiker Guide to GNU C

Renaud Cerrato
5 min readJan 23, 2019
Illustration: Joe deSousa

Being an embedded developer for so many years, I’ve spend more time with GCC than any other tool, and getting the most of it have been a pleasant journey.

The following is condensing my favorites GCC tricks and tips in no particular order, and will get updated over time and suggestions.

If portability matters to you, you should probably look elsewhere. But if you’re a Linux developer, a creative Arduino maker, or an embedded developer there’s a chance that GCC is the only targeted compiler. So, why not taking the convenient road? After all, the Linux Kernel source code isn’t portable, and nobody cares.

Variable Cleanup Function

The cleanup variable attribute runs a function when the variable goes out of scope. The function will be passed a pointer to the variable as a convenience:

One of my favorite usage of the cleanup attribute is to automatically release a lock within a method accessing a mutually exclusive resource:

Weak Function

The weak function attribute causes the declaration to be emitted as a weak symbol instead of global, which makes it overridable:

As a nice side-effect, undefined weak functions are evaluating to null and could come in handy, for example, to implement some optional user-defined hooks into your library:

Finally, the weak function attribute pairs extremely well with alias to declare a default implementation:

Automatic Type Inference

GNU C introduced the __auto_type keyword. Maybe you’re already aware of typeof to refer to the type of an expression:

A typeof construct can be used anywhere a typedef name can be used: you can use it in a declaration, in a cast, or inside of sizeof or typeof.

In GNU C, similar to the C++11 auto keyword, you may also declare the type of a variable as __auto_type:

The macro above operates on any arithmetic type and evaluates each of its arguments only once.

The advantage of __auto_type in the macro above is that each argument to the macro appears only when expanded, preventing the size of the macro expansion growing exponentially when calls to such macros are nested inside arguments of such macros. Moreover, if the argument to the macro type has variably modified type, it is evaluated only once when using __auto_type, but twice if typeof is used.

Wrapper Function

The GNU linker --wrap=symbol option provides a wrapper function for a given symbol. The wrapper function should be called __wrap_symbol and the wrapped function can be called through __real_symbol :

Case Ranges

GCC allows range of consecutive values to be specified in a single case label:

Designated Initializers

ISO C99 relaxed elements initialization by allowing array indices or structure field names to be specified during initialization. GNU C allows this extension in C90 mode as well, along with range-initialization of arrays:

Cast to Union

A cast to union type is similar to other casts, except that the type specified is a union type:

A cast to union is actually a constructor, not a cast, and hence does not yield an lvalue like normal casts (see compound literals).

Unnamed Structure Fields

Introduced in ISO C11, unnamed structure and union fields were supported well before by GCC:

One of the most straightforward usage of such feature is decomposition which also pairs extremely well with cast-to-union and bit fields. Please note that the examples below support little-endian byte order only for brevity:

half-word decomposition
ieee754 float decomposition

Constructor Function

The constructor function attribute causes the function to be called automatically before the execution enters main(). Similarly, the destructor attribute causes the function to be called automatically after main() completes or exit() is called:

You may provide an optional integer priority to control the order in which constructor and destructor functions are run. A constructor with a smaller priority number runs before a constructor with a larger priority number; the opposite relationship holds for destructors:

Compound Literals

A compound literal designates an unnamed object: its value is an object of the type specified in the cast, it’s an lvalue. Supported in ISO C99, GCC also supports compound literals in C90 mode:

Removing pointless variables
inline arrays

Nested Functions

A nested function is a function defined inside another function. Thanks to lexical scoping, the nested function can access all the variables of the containing function that are visible at the point of the definition:

source: Wikipedia

Zero Length Arrays

Zero-length arrays are allowed in GNU C and are really useful as the last element of a structure that is an header to a variable-length object:

Beware that non-empty initialization of zero-length arrays is treated like excess elements and are ignored: as an alternative (and convenience), GCC allows static initialization of flexible array member:

Arrays of Variable Length

Variable-length arrays are allowed in ISO C99 and GCC accepts them in C90 mode as an extension:

Support for offsetof (and beyond)

The macro offsetof evaluates to the offset (in bytes) of a given member within a struct or union type. The offsetof macro takes two parameters, the first being a structure name, and the second being the name of a member within the structure:

A real-life example of the offsetof macro would be the Linux Kernel container_of macro:

Transparent Union

The transparent_union variable attribute, when attached to a union type definition, indicates that any function parameter having that union type causes calls to that function to be treated in a special way: the argument corresponding to a transparent union type can be of any type in the union; no cast is required:

Stringizing

When a macro parameter is used with a leading #, the preprocessor replaces it with the literal text of the actual argument, converted to a string constant:

Beware that stringizing the result of the expansion of a macro argument requires two levels of macros:

Concatenation

Merging two tokens into one while expanding macros can be useful. The ## preprocessing operator performs token concatenation:

I’d recommend to use some helpers to include for re-use:

Repeat Macro

Thanks to the concatenation preprocessing operator, a REPEAT helper macro can be written to achieve repetitive constructs:

Poor Man’s Templating

The concatenation preprocessing operator, along with #include, allows some sort of basic templating:

Compile-Time Assertions

C11 introduced the _Static_assert keyword for compile-time assertions but if you’re running GCC 4.5 or below, here’s a workaround:

source: StackOverflow

That’s all for now! The above article has been written with ❤, feel free to share and don’t forget to clap if you liked it!

--

--

Renaud Cerrato

Analog at birth but digital by design. Hardcore Android Developer. Linux devotee. Came back once from /dev/null.