Hay muchos usos para tal cosa.
Por ejemplo, una es para que la macro tenga un comportamiento diferente en las compilaciones diferentes. Por ejemplo, si desea que los mensajes de depuración, podría tener algo como esto:
#ifdef _DEBUG
#define DEBUG_LOG(X, ...) however_you_want_to_print_it
#else
#define DEBUG_LOG(X, ...) // nothing
#endif
Otro uso podría ser para personalizar el archivo de cabecera basa en su sistema. Esto es de mi cabecera OpenGL implementado-mesa en Linux:
#if !defined(OPENSTEP) && (defined(__WIN32__) && !defined(__CYGWIN__))
# if defined(__MINGW32__) && defined(GL_NO_STDCALL) || defined(UNDER_CE) /* The generated DLLs by MingW with STDCALL are not compatible with the ones done by Microsoft's compilers */
# define GLAPIENTRY
# else
# define GLAPIENTRY __stdcall
# endif
#elif defined(__CYGWIN__) && defined(USE_OPENGL32) /* use native windows opengl32 */
# define GLAPIENTRY __stdcall
#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 303
# define GLAPIENTRY
#endif /* WIN32 && !CYGWIN */
#ifndef GLAPIENTRY
#define GLAPIENTRY
#endif
y se utiliza en las declaraciones de cabecera como:
GLAPI void GLAPIENTRY glClearIndex(GLfloat c);
GLAPI void GLAPIENTRY glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
GLAPI void GLAPIENTRY glClear(GLbitfield mask);
...
(I eliminado la parte de GLAPI
)
Así se obtiene la imagen , una macro que se usa en algunos casos y no se usa en otros casos podría definirse como algo en esos casos y nada en esos otros casos.
Otros casos podría ser la siguiente:
Si la macro no toma parámetros, que podría ser sólo para declarar algún caso. Un ejemplo famoso es proteger los archivos de encabezado. Otro ejemplo sería algo como esto
#define USING_SOME_LIB
y más tarde podría ser utilizado como esto:
#ifdef USING_SOME_LIB
...
#else
...
#endif
Podría ser que la macro se utilizó en algún momento de hacer algo (por ejemplo, registro), pero luego en el lanzamiento, el propietario decidió que el registro ya no es útil y simplemente eliminó el contenido de la macro para que quede vacío. Sin embargo, esto no es recomendable, use el método que mencioné al principio de la respuesta.
Por último, podría estar allí sólo para una explicación más detallada, por ejemplo, se puede decir
#define DONT_CALL_IF_LIB_NOT_INITIALIZED
y escribir funciones como:
void init(void);
void do_something(int x) DONT_CALL_IF_LIB_NOT_INITIALIZED;
Aunque este último caso es un poco absurdo, pero tendría sentido en tal caso:
#define IN
#define OUT
void function(IN char *a, OUT char *b);
Esto puede ser útil en conjunción con otro conjunto de directivas que permiten la compilación condicional. Un #define sin una cadena de token elimina las apariciones de identificador del archivo de origen. El identificador permanece definido y puede ser probado usando las directivas #if defined y #ifdef. – AminM