C/C++ 预处理指令
1. 文件包含
在C/C++中,#include
指令用于包含头文件。根据文件名的不同引用方式,有两种形式:
#include "filename"
:首先在源文件所在的目录中查找文件。如果找不到,再在系统默认的目录中查找。#include <filename>
:直接从系统默认的目录中查找文件。
示例代码:
// myheader.h
#ifndef MYHEADER_H
#define MYHEADER_H
void sayHello();
#endif // MYHEADER_H
// myheader.cpp
#include "myheader.h"
#include <iostream>
void sayHello() {
std::cout << "Hello, World!" << std::endl;
}
// main.cpp
#include "myheader.h"
int main() {
sayHello();
return 0;
}
在上述代码中,myheader.h
和 myheader.cpp
包含了函数的声明和定义,而 main.cpp
包含了头文件 myheader.h
并调用了 sayHello
函数。
2. 宏替换
宏定义用于替换代码中的文本片段。在宏定义中,有一些细节需要注意:
2.1 宏定义末尾不加分号
如果在宏定义的末尾加上分号,宏替换时会引入多余的分号。
示例代码:
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int main() {
int x = 5, y = 10;
int maxVal = MAX(x, y); // 这里不能加分号
printf("Max value: %d\n", maxVal);
return 0;
}
在上面的代码中,MAX
宏用于计算两个数的最大值。
2.2 宏替换中的运算符优先级
在宏定义中,确保使用括号以避免运算符优先级问题。
示例代码:
#define A (2+2)
#define B (3+3)
#define C (A*B)
int main() {
printf("%d\n", C); // 结果是 (2+2)*(3+3) = 4*6 = 24
return 0;
}
在上述代码中,使用括号确保了运算顺序正确。
2.3 带有副作用的宏参数
宏参数可能会引起副作用,如 x++
会改变 x
的值。
示例代码:
#define INCREMENT(x) ((x) + 1)
int main() {
int a = 5;
int b = INCREMENT(a++); // 结果是 ((5++) + 1) = 6
printf("a: %d, b: %d\n", a, b); // 输出 a: 6, b: 6
return 0;
}
在上述代码中,a
的值在宏替换中被改变。
3. 预定义符号
C/C++ 中有一些预定义符号可以在编译时获取文件名、行号、编译日期和时间等信息。
示例代码:
#include <stdio.h>
int main() {
printf("File: %s\n", __FILE__);
printf("Line: %d\n", __LINE__);
printf("Date: %s\n", __DATE__);
printf("Time: %s\n", __TIME__);
return 0;
}
在上述代码中,预定义符号用于打印当前文件名、行号、编译日期和时间。
4. #
和 ##
4.1 #
符号
#
符号用于将宏参数转化为字符串。
示例代码:
#define TO_STRING(x) #x
int main() {
printf("String: %s\n", TO_STRING(Hello, World!)); // 输出 "Hello, World!"
return 0;
}
在上述代码中,TO_STRING
宏将参数转化为字符串。
4.2 ##
运算符
##
运算符用于连接两个宏参数。
示例代码:
#define CONCAT(a, b) a##b
int main() {
int xy = 100;
printf("Value: %d\n", CONCAT(x, y)); // 输出 100
return 0;
}
在上述代码中,CONCAT
宏将参数连接成一个标识符。
5. 其他指令
5.1 #ifdef
和 #ifndef
这两个指令用于条件编译,#ifdef
判断某个宏是否被定义,#ifndef
判断某个宏是否未被定义。
示例代码:
#define DEBUG
int main() {
#ifdef DEBUG
printf("Debug mode\n");
#else
printf("Release mode\n");
#endif
return 0;
}
在上述代码中,根据是否定义了 DEBUG
宏,选择编译不同的代码段。
5.2 #if
和 #endif
#if
指令用于更复杂的条件编译,可以进行算术和逻辑运算。
示例代码:
#define VERSION 2
int main() {
#if VERSION == 1
printf("Version 1\n");
#elif VERSION == 2
printf("Version 2\n");
#else
printf("Unknown version\n");
#endif
return 0;
}
在上述代码中,根据 VERSION
宏的值选择编译不同的代码段。
5.3 #undef
#undef
用于取消宏定义。
示例代码:
#define TEMP 100
int main() {
printf("TEMP: %d\n", TEMP);
#undef TEMP
// printf("TEMP: %d\n", TEMP); // 这行会报错,因为 TEMP 已经被取消定义
return 0;
}
在上述代码中,TEMP
宏在 #undef
指令之后被取消定义,后续无法再使用。