C语言#ifdef和#ifndef命令的用法(非常详细)

 
在C语言中,和条件编译有关的预处理命令有 #if、#elif、#else、#endif、#ifdef 和 #ifndef。前面四个命令已经在《C语言 #if、#elif、#else 和 #endif 的用法》中讲解过了,本文我们继续讲解 #ifdef 和 #ifndef 的用法。

#ifdef 是 if defined 的缩写,也即“是否定义”的意思;#ifndef 是 if not defined 的缩写,也即“是否未定义”的意思。它们会根据「某个宏是否被定义」来控制代码的编译过程。

#ifdef 和 #ifndef 命令的用法类似,如下所示:
#ifdef MACRO_NAME
    //代码段1
    //如果 MACRO_NAME 宏已被定义,则编译 代码段1
#elif 常量表达式
    //代码段2
    //如果 常量表达式 的值为真,则编译 代码段2
#else
    //代码段n
    //如果以上条件都不满足,则编译 代码段n
#endif

#ifndef MACRO_NAME
    //代码段1
    //如果 MACRO_NAME 宏未被定义,则编译 代码段1
#elif 常量表达式
    //代码段2
    //如果 常量表达式 的值为真,则编译 代码段2
#else
    //代码段n
    //如果以上条件都不满足,则编译 代码段n
#endif
MACRO_NAME 是宏的名字。对于 #ifdef 命令来说,它会检查该宏是否已被定义:如果该宏已被定义,那么编译代码段1,否则继续匹配后面的 #elif 和 #else,编译其它代码段。

#ifndef 恰好相反,它会检查该宏是否未被定义:如果该宏未被定义,那么编译代码段1,否则继续匹配后面的 #elif 和 #else,编译其它代码段。

当然,#elif 和 #else 分支都是可以省略的。

你完全可以把 #ifdef 看作#if defined( )的简写,把 #ifndef 看作#if !defined( )的简写。

示例1:#ifdef 的简单用法。
#include <stdio.h>

int main() {
    #ifdef _DEBUG
        printf("正在使用 Debug 模式编译程序...\n");
    #else
        printf("正在使用 Release 模式编译程序...\n");
    #endif

    return 0;
}
对于 Visual Studio,当以 Debug 模式编译程序时,宏 _DEBUG 会被定义,预处器会保留第 5 行代码,删除第 7 行代码。反之会删除第 5 行,保留第 7 行。

示例2:#ifndef 经常用于头文件的包含保护,以防止同一个头文件被多次包含,让我们通过一个例子来说明这种用法。
// 文件名:myheader.h
#ifndef MYHEADER_H
#define MYHEADER_H

// 头文件内容
struct MyStruct {
    int x;
    int y;
};

void my_function();

#endif // MYHEADER_H
在这个例子中,当第一次包含 myheader.h 文件时,MYHEADER_H 宏未定义,所以预处理器会定义这个宏,并编译头文件的内容。如果在同一个源文件中再次包含这个头文件,由于 MYHEADER_H 已经被定义,预处理器会跳过整个头文件的内容,从而避免重复定义和编译错误。

示例3:#ifdef 和 #ifndef 还可以和 #else、#elif 结合使用,以实现更复杂的逻辑判断。请看下面的代码:
#include <stdio.h>

#define PLATFORM_LINUX

int main() {
    #ifdef PLATFORM_WINDOWS
        printf("Running on Windows\n");
    #elif defined(PLATFORM_LINUX)
        printf("Running on Linux\n");
    #elif defined(PLATFORM_MACOS)
        printf("Running on macOS\n");
    #else
        printf("Unknown platform\n");
    #endif

    return 0;
}
运行结果:

Running on Linux

在这个例子中,我们使用条件编译来为不同的操作系统生成不同的代码。根据定义的宏,程序会输出相应的平台信息。这种方法在编写跨平台代码时非常有用,你可以在同一个源文件中包含针对不同平台的代码。