C 语言中的 #ifndef

Jinku Hu 2023年1月30日 2021年2月7日
  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);
}
Author: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn