stop defining feature-test macros in your code

If there is any change in the C world I would like to see in 2022, it would be the abolition of #define _GNU_SOURCE. In many cases, defining this macro in C code can have harmful side effects ranging from subtle breakage to miscompilation, because of how feature-test macros work.

When writing or studying code, you’ve likely encountered something like this:

#define _GNU_SOURCE
#include <string.h>

Or worse:

#include <stdlib.h>
#include <unistd.h>
#include <string.h>

The #define _XOPEN_SOURCE and #define _GNU_SOURCE in those examples are defining something known as a feature-test macro, which is used to selectively expose function declarations in the headers. These macros are necessary because some standards have conflicting definitions of functions and thus are aliased to other symbols, allowing co-existence of the conflicting functions, but only one version of that function may be defined at a time, so the feature-test macros allow the user to select which definitions they want.

The correct way to use these macros is by defining them at compile time with compiler flags, e.g. -D_XOPEN_SOURCE or -std=gnu11. This ensures that the declared feature-test macros are consistently defined while compiling the project.

As for the reason why #define _GNU_SOURCE is a thing? It’s because we have documentation which does not correctly explain the role of feature-test macros. Instead, in a given manual page, you might see language like “this function is only enabled if the _GNU_SOURCE macro is defined.”

To find out the actual way to use those macros, you would have to read feature_test_macros(7), which is usually not referenced from individual manual pages, and while that manual page shows the incorrect examples above as bad practice, it understates how much of a bad practice it actually is, and it is one of the first code examples you see on that manual page.

In conclusion, never use #define _GNU_SOURCE, always use compiler flags for this.

5 replies on “stop defining feature-test macros in your code”

(Long time reader, first time commentor)

Can you give an example of subtle breakage or miscompilation from defining a feature test macro in a source file?

A good example is GNU strerror_r which is slightly different than POSIX strerror_r. Unless you declare the macro at the very beginning, you can wind up in a situation where you have the wrong function.

This can also interact poorly with things like _FORTIFY_SOURCE depending on how it is implemented, where the fortify headers have a different configuration than expected.

But if you do define a macro at the very top of the source file without including anything else, you won’t have the problems caused by these inconsistencies.

Comments are closed.