文章目录
一、C 预处理器
C预处理器(C Preprocessor)是C语言编译器的一个组成部分,它负责在编译过程之前处理源代码。预处理器的主要任务是扫描源代码,对其中的预处理指令进行解释和替换,然后输出一个修改后的源代码文件,这个文件随后会被C编译器处理。
C预处理器指令都以#符号开始,并且必须在每行的开头(前面不能有任何空格或制表符)。下面是一些常见的C预处理器指令:
- #include:包含另一个文件的内容。有两种形式:
- #include <filename>:从标准库路径中搜索- filename文件。
- #include "filename":首先在当前目录或指定的目录中搜索- filename文件,如果找不到,再从标准库路径中搜索。
- #define:定义一个宏。例如,- #define PI 3.14159会将源代码中所有的- PI替换为- 3.14159。
- #undef:取消之前由- #define定义的宏。
- #if、- #elif、- #else、- #endif:条件编译指令,允许你根据条件包含或排除代码段。
- #ifdef、- #ifndef:检查某个宏是否已经被定义。
- #line:改变编译器的行号和文件名,这在创建报告错误和警告的宏时很有用。
- #error和- #warning:生成编译时错误或警告。
- #pragma:这是预处理器的扩展指令,它允许向编译器发送特定的指令,这些指令可能因编译器而异。
预处理器指令在源代码被编译之前执行,并且通常不会生成目标代码。它们主要用于处理代码中的常量和宏定义,以及控制代码中的条件编译。预处理器指令在大型项目中特别有用,因为它们可以帮助组织和管理代码,减少冗余,并允许在不同的编译配置之间切换。
二、C 预处理器指令
C预处理器指令在C语言编程中非常有用,它们允许你在编译前对源代码进行各种处理。以下是一些C预处理器指令的详细代码案例:
1. #include
 
// 使用尖括号包含标准库头文件
#include <stdio.h>
// 使用双引号包含用户定义的头文件
#include "myheader.h"
int main() {
    printf("Hello, World!\n"); // 假设myheader.h中没有任何与此冲突的声明
    return 0;
}
2. #define 和 #undef
 
#define PI 3.14159
int main() {
    double circle_area = PI * 5 * 5; // 使用PI宏替换为3.14159
    printf("Circle area is %.2f\n", circle_area);
    
    #undef PI // 取消PI的宏定义
    // 下面的代码会导致编译错误,因为PI已经被undef了
    // double another_area = PI * 3 * 3;
    
    return 0;
}
3. #if、#elif、#else 和 #endif
 
#define DEBUG 1
int main() {
    #if DEBUG
        printf("Debugging is on\n");
    #elif defined(TEST)
        printf("Testing is on\n");
    #else
        printf("Neither debugging nor testing is on\n");
    #endif
    
    return 0;
}
在这个例子中,DEBUG被定义为1,所以程序会输出"Debugging is on"。如果你注释掉#define DEBUG 1并取消注释#define TEST 1,程序会输出"Testing is on"。
4. #ifdef 和 #ifndef
 
// 假设没有定义MY_FEATURE
int main() {
    #ifdef MY_FEATURE
        printf("My feature is enabled\n");
    #else
        printf("My feature is disabled\n");
    #endif
    
    #ifndef MY_FEATURE
        printf("Again, my feature is disabled\n");
    #endif
    
    return 0;
}
在这个例子中,因为MY_FEATURE没有被定义,所以两个printf都会执行,分别输出"My feature is disabled"和"Again, my feature is disabled"。
5. #line
 
这个指令通常用于调试目的,允许你改变编译器的行号和文件名。在实际编程中较少直接使用。
6. #error 和 #warning
 
#if !(defined(WIN32) || defined(__unix__) || defined(__APPLE__))
    #error Unsupported platform!
#endif
int main() {
    // ...
    return 0;
}
在这个例子中,如果代码不是在Windows、Unix或Apple平台上编译的,预处理器会生成一个错误消息"Unsupported platform!"。
7. #pragma
 
#pragma指令是特定于编译器的,用于提供编译器的特定指令。例如,在某些编译器中,你可以使用#pragma once来确保头文件只被包含一次。
// myheader.h
#pragma once
// ... 其余的头文件内容
注意:#pragma once并不是C语言标准的一部分,但它在许多现代编译器中都被支持。在编写跨平台代码时,你应该避免依赖非标准的预处理器指令。
三、C 预定义宏
C语言预处理器提供了一些预定义的宏,这些宏在编译时总是可用的,而无需显式地定义它们。这些预定义宏通常用于获取关于编译器和编译环境的信息。下面是一些常见的C预定义宏及其详细代码案例:
1. __LINE__
 
这个宏被预处理器替换为当前源代码行号(十进制整数)。
#include <stdio.h>
int main() {
    printf("This is line %d\n", __LINE__);
    printf("This is line %d\n", __LINE__ + 1); // 下一行
    return 0;
}
2. __FILE__
 
这个宏被预处理器替换为当前源代码文件的名称(带路径或不带路径,取决于编译器)。
#include <stdio.h>
int main() {
    printf("This file is %s\n", __FILE__);
    return 0;
}
3. __DATE__
 
这个宏被预处理器替换为编译时的日期,格式为 “Day Mon DD HH:MM:SS YYYY\n”。
#include <stdio.h>
int main() {
    printf("Compilation date: %s", __DATE__);
    return 0;
}
4. __TIME__
 
这个宏被预处理器替换为编译时的时间,格式为 “HH:MM:SS”。
#include <stdio.h>
int main() {
    printf("Compilation time: %s", __TIME__);
    return 0;
}
5. __STDC__
 
如果编译器遵循C语言标准,此宏被设置为1。否则,它未定义。
#include <stdio.h>
int main() {
    #if __STDC__
        printf("This is a C Standard compliant compiler\n");
    #else
        printf("This is not a C Standard compliant compiler\n");
    #endif
    return 0;
}
6. __STDC_VERSION__
 
如果编译器遵循C99或更新的标准,此宏将被设置为一个表示C标准版本的整数。例如,对于C99,它是199901L。如果不支持C99或更新的标准,此宏可能未定义。
#include <stdio.h>
int main() {
    #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
        printf("This compiler supports C99 or newer\n");
    #else
        printf("This compiler does not support C99 or newer\n");
    #endif
    return 0;
}
7. __cplusplus
 
当代码在C++编译器中编译时,此宏被设置为1。在C编译器中,它未定义。
注意:这个宏主要用于区分C和C++代码,而不是在C语言代码中使用。
8. 编译器特定的预定义宏
除了上述标准的预定义宏之外,不同的编译器还可能提供自己的预定义宏。例如,GCC提供了__GNUC__、__GNUC_MINOR__、__GNUC_PATCHLEVEL__等宏来表示GCC的版本信息。
四、相关链接
- Visual Studio Code下载地址
- Sublime Text下载地址
- 「C系列」C 简介
- 「C系列」C 基本语法
- 「C系列」C 数据类型
- 「C系列」C 变量及常见问题梳理
- 「C系列」C 常量
- 「C系列」C 存储类
- 「C系列」C 运算符
- 「C系列」C 判断/循环
- 「C系列」C 函数
- 「C系列」C 作用域规则
- 「C系列」C 数组
- 「C系列」C enum(枚举)
- 「C系列」C 指针及其应用案例










