C 语言中的 #ifndef
Jinku Hu
2023年10月12日
本文将演示如何在 C 语言中使用 #ifndef
避免重入包含的多种方法。
在 C 语言中使用 ifndef
保护头文件不被多次包含
C 语言中的头文件用于定义同名源文件中实现的函数的接口。接口通常包括函数原型、公开访问的数据结构的定义以及其他一些杂项。
注意,头文件可能会多次包含在源文件中,导致编译器出错。通常情况下,用 #ifndef
预处理器指令可以防止这种情况发生,这个指令叫做包装器 #ifndef
。当头文件的内容被封装成如下例所示的结构时,其中指令 #ifndef MY_GUARD
是起点,#endif
是终点。ifndef
指令检查是否定义了 MY_GUARD
宏,如果没有则继续,用下一个指令定义。如果用户第二次包含相同的头,ifndef
指令将评估为 false,并忽略 #endif
指令之前的代码。因此,编译器将只从这个头文件中得到一份代码,并成功编译。
#include <stdio.h>
#ifndef MY_GUARD
#define MY_GUARD 1
#define PER(D) #D
#define JOIN(A, B) (A##B)
#define JOINX(A, B) JOIN(A, B)
int power(int base, int n) {
int p = base;
for (size_t i = 0; i < n; i++) {
p *= base;
}
return p;
}
#endif
另一种达到同样效果的方法是在头文件中包含 #pragma once
指令。预处理器只对这些头文件扫描一次,并保证不被再次读取。下面的方法有一个缺点,就是它在不同的预处理器之间的可移植性很低,所以大家不妨坚持使用包装器 #ifndef
方法,以保证代码库有更好的灵活性。
#include <stdio.h>
#pragma once
#define PER(D) #D
#define JOIN(A, B) (A##B)
#define JOINX(A, B) JOIN(A, B)
int power(int base, int n) {
int p = base;
for (size_t i = 0; i < n; i++) {
p *= base;
}
return p;
}
使用 ifndef
指令来确保宏在 C 语言中不会被多次定义
另外,我们也可以使用 ifndef
指令检查给定的宏表达式是否已经被定义。逻辑工作原理和上一个例子完全一样,如果表达式没有被定义,下一个 #define
指令就会进行相应的处理。#ifndef
和 #endif
之间只有一行是一个宏定义,这意味着如果条件为假,只跳过给定的宏定义。
#include <stdio.h>
#include <stdlib.h>
#define PER(D) #D
#ifndef DLEVEL
#define DLEVEL 6
#endif
int main() {
for (int j = 0; j < DLEVEL; ++j) {
printf("%s\n", PER(stringify this));
}
exit(EXIT_SUCCESS);
}