features.h: Feature Test Macros

With which C standard (C89, C99, C11, etc.) you are compiling your code decides which features are available. For example, pthread-barriers are not present under C99. If you come across a scenario when the compiler fires an error saying something is not defined, even though, it seems to be present in the included header, then probably it is because some how that definition was excluded by the preprocessor because the feature is disabled. To properly enable particular feature, we needed to define appropriate macros that are present in features.h.

The macros can be either defined in the C code, or can be passed from -D option of GCC. Following are the list of macros defined in features.h:

 _POSIX_SOURCE : (deprecated) 
 _POSIX_C_SOURCE : POSIX series of standards
 _XOPEN_SOURCE/_XOPEN_SOURCE_EXTENDED : X/Open Unix standards
 _LARGEFILE_SOURCE : Enable large files
 _LARGEFILE64_SOURCE : Enable large files in 64-bits
 _FILE_OFFSET_BITS : Enable 64-bit file offset
 _ISOC99_SOURCE : ISO C standard
 _GNU_SOURCE : ISO C89, ISO C99, POSIX.1, POSIX.2, BSD, SVID, X/Open, 
               LFS, and GNU extensions
 _DEFAULT_SOURCE : POSIX 2008, BSD and SVID features
 _REENTRANT/_THREAD_SAFE : POSIX.1c/pthreads

Most of the errors, most of the times, could be resolved by setting _XOPEN_SOURCE appropriately.

_XOPEN_SOURCE < 500
    is same as _POSIX_C_SOURCE = 2.

500 <= _XOPEN_SOURCE < 600 
    is same as _POSIX_C_SOURCE = 199506L.

600 <= _XOPEN_SOURCE < 700 
    is same as _POSIX_C_SOURCE = 200112L.

700 <= _XOPEN_SOURCE (since glibc 2.10)
    is same as _POSIX_C_SOURCE = 200809L.

_XOPEN_SOURCE >= 500 
    is same as defining _XOPEN_SOURCE_EXTENDED

To look into when this helps, consider the following example:
example.c

#include <pthreads.h>

// Barrier variable
pthread_barrier_t barr;

void * entry_point(void *arg)
{
    int rc = pthread_barrier_wait(&barr);
    if (rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD) {
        return NULL;
    }
}

When compiling with C99 standard, it throws an error: The definition of pthread_barrier_t, pthread_barrier_wait and PTHREAD_BARRIER_SERIAL_THREAD exists in pthread.h, but are defined only if __USE_XOPEN2K macro is defined. Having said that, internal macros like __USE_XOPEN2K are not supposed to be defined in user programs. This is because the barrier feature was added post C99.

$ gcc -std=c99 example.c -lpthread -c
 example.c:5:1: error: unknown type name ‘pthread_barrier_t’
 pthread_barrier_t barr;
 ^
 example.c: In function ‘entry_point’:
 example.c:10:5: warning: implicit declaration of function ‘pthread_barrier_wait’ [-Wimplicit-function-declaration]
 int rc = pthread_barrier_wait(&barr);
 ^
 example.c:11:25: error: ‘PTHREAD_BARRIER_SERIAL_THREAD’ undeclared (first use in this function)
 if(rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD)
 ^
 example.c:11:25: note: each undeclared identifier is reported only once for each function it appears in

A user program must set one of the macros from features.h which, in turn, will set other internal macros like __USE_XOPEN2K. For instance, __USE_XOPEN2K is defined in features.h, and the user program enables it by setting _XOPEN_SOURCE=600.

features.h:
# if (_XOPEN_SOURCE - 0) >= 600
...
# define __USE_XOPEN2K 1
...
# endif

Compiling,

$ gcc -std=c99 example.c -lpthread -c -D_XOPEN_SOURCE=600

These are precisely meant to enable and disable different sets of functionalities in C libraries, as defined by the portability standards (ISO, X/Open, etc.), over different platforms/operating-systems.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s