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