These preprocessing directives are declared in the C++ Standard the following way
if-section:
if-group elif-groupsopt else-groupopt endif-line
if-group:
# if constant-expression new-line groupopt
# ifdef identifier new-line groupopt
# ifndef identifier new-line groupopt
elif-groups:
elif-group
elif-groups elif-group
elif-group:
# elif constant-expression new-line groupopt
else-group:
# else new-line groupopt
endif-line:
# endif new-line
control-line:
For example directives
#ifdef and
#ifndef check whether the identifier used in the directive is or is not defined as a macro name. Based on this the compiler can either include or skip the code followed the directives in the compilation unit.
For example let assume that some code snippet in a C program allocates memory.
For debug version of the program you could check whether the memory was indeed allocated. In this case you could write
#include <stdlib.h>
#include <assert.h>
int main(void)
{
char *p = NULL;
// ... some code that has to allocate a memory pointed to by p
assert( p );
}
If the directive
#define NDEBUG is not present and p will be equal to NULL then the program will abend because it would not pass the statement with assert.
However if you will include the directive as it is done in the example above and p will be equal to NULL neverthe less the assert will be ignored.
#include <stdlib.h>
#define NDEBUG
#include <assert.h>
int main(void)
{
char *p = NULL;
// ... some code that has to allocate a memory pointed to by p
assert( p );
}
The assert macro uses the directive
#ifdef NDEBUG
inside its own definition something as
#ifdef NDEBUG
#define assert(_Expression) ((void)0)
#else
// definition of assert that issues an error
and behaves accordingly.
You can find more information about these directives in books on C/C++ or in internet.