Существует множество вариантов использования такой вещи.
Например, один макрос должен иметь разное поведение в разных сборках. Например, если вы хотите отладочные сообщения, вы можете получить что-то вроде этого:
#ifdef _DEBUG
#define DEBUG_LOG(X, ...) however_you_want_to_print_it
#else
#define DEBUG_LOG(X, ...) // nothing
#endif
Другое использование может быть для настройки вашего заголовочного файла в зависимости от вашей системы. Это из моего реализованного в mesa заголовка OpenGL в 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
И используется в объявлениях заголовков, таких как:
GLAPI void GLAPIENTRY glClearIndex( GLfloat c );
GLAPI void GLAPIENTRY glClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha );
GLAPI void GLAPIENTRY glClear( GLbitfield mask );
...
(я удалил часть для GLAPI
)
Таким образом, вы получите картину, макрос, который используется в некоторых случаях и не используется в других случаях, может быть определен для чего-то в этих случаях и ничего для этих других случаев.
Другие случаи могут быть следующими:
Если макрос не принимает параметры, это может быть просто объявить некоторый случай. Известный пример - защита заголовочных файлов. Другим примером будет что-то вроде этого
#define USING_SOME_LIB
и позже можно использовать так:
#ifdef USING_SOME_LIB
...
#else
...
#endif
Возможно, что макрос использовался на каком-то этапе, чтобы что-то сделать (например, журнал), но затем при выпуске владелец решил, что журнал больше не нужен, и просто удалил содержимое макроса, чтобы он стал пустым. Это не рекомендуется, однако, используйте метод, который я упомянул в самом начале ответа.
Наконец, это может быть просто для дополнительного объяснения, например, вы можете сказать
#define DONT_CALL_IF_LIB_NOT_INITIALIZED
и вы пишете такие функции, как:
void init(void);
void do_something(int x) DONT_CALL_IF_LIB_NOT_INITIALIZED;
Хотя этот последний случай немного абсурден, но в таком случае это имело бы смысл:
#define IN
#define OUT
void function(IN char *a, OUT char *b);