C 语言中的 #ifndef

Jinku Hu 2023年10月12日
  1. 在 C 语言中使用 ifndef 保护头文件不被多次包含
  2. 使用 ifndef 指令来确保宏在 C 语言中不会被多次定义
C 语言中的 #ifndef

本文将演示如何在 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);
}
作者: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

DelftStack.com 创始人。Jinku 在机器人和汽车行业工作了8多年。他在自动测试、远程测试及从耐久性测试中创建报告时磨练了自己的编程技能。他拥有电气/电子工程背景,但他也扩展了自己的兴趣到嵌入式电子、嵌入式编程以及前端和后端编程。

LinkedIn Facebook