首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言預處理指令詳解:宏定義、條件編譯與文件包含

     編輯:關於C語言

C語言預處理指令詳解:宏定義、條件編譯與文件包含

預處理指令在編譯前執行,以 # 開頭,不屬於 C 語言語句範疇,不以分號結束。三大類:宏定義、條件編譯、文件包含。

一、無參數宏定義

基本語法與特性

#define MACRO_NAME replacement_text
  • 作用域:從定義行開始至文件結尾,可用 #undef 終止
  • 宏名慣用全大寫或 k 開頭,與變量名區分
  • 字符串字面量中的宏名不會被替換
  • 預處理階段單純文本替換,不進行類型檢查

示例

#include <stdio.h>

#define COUNT 4

int main() {
    char *name = "COUNT";  // 字符串內不替換
    printf("%s\n", name);  // 輸出 COUNT
    
    int ages[COUNT] = {1, 2, 67, 89};
    for (int i = 0; i < COUNT; i++) {
        printf("%d\n", ages[i]);
    }
    
    #undef COUNT  // 取消宏定義
    // int a = COUNT; // 錯誤:COUNT 已失效
    return 0;
}

二、帶參數宏定義:類函數宏

定義規範:括號至關重要

#define SUM(v1, v2) ((v1) + (v2))
#define SQUARE(a)   ((a) * (a))

黃金法則:參數與整體表達式都要加括號,防止運算符優先級導致錯誤。

對比:宏 vs 函數

特性宏函數
執行階段預處理(文本替換)運行時(調用開銷)
類型檢查無有
代碼膨脹可能(每次調用展開)無(單一實體)
調試可見性差(無符號表)好
適用場景簡單、高頻、類型無關操作複雜邏輯、需類型安全

陷阱演示

#define SQUARE(a) ((a)*(a))

int main() {
    int c = SQUARE(5+5) / SQUARE(2);
    // 展開:((5+5)*(5+5)) / ((2)*(2)) = 100 / 4 = 25 ✓
    
    // 若無外層括號:#define SQUARE(a) a*a
    // SQUARE(5+5) -> 5+5*5+5 = 35 ✗
    // SQUARE(5+5)/SQUARE(2) -> 5+5*5+5/2*2 = 5+25+2.5*2 = 35 ✗
    
    printf("c = %d\n", c); // 25
    return 0;
}

三、條件編譯

常用指令

  • #ifdef MACRO / #ifndef MACRO:宏是否定義
  • #if constant_expr / #elif / #else / #endif:常量表達式判斷
  • #error message:編譯報錯

典型應用:防止頭文件重複包含

// myheader.h
#ifndef MYHEADER_H
#define MYHEADER_H

// 內容...

#endif

跨平台編譯控制

#ifdef _WIN32
    #include 
#elif defined(__linux__)
    #include 
#else
    #error "Unsupported platform"
#endif

四、文件包含

#include    // 系統頭文件,搜尋標準路徑
#include "mydefs.h"  // 用戶頭文件,優先搜尋當前目錄

包含文件內容會原位展開,等同於手動複製代碼。

五、預定義宏

編譯器內建,不可重定義:

  • __FILE__:當前源文件名
  • __LINE__:當前行號
  • __DATE__:編譯日期 "Mmm dd yyyy"
  • __TIME__:編譯時間 "hh:mm:ss"
  • __STDC__:是否符合 ANSI C 標準
  • __cplusplus:C++ 編譯器標識

調試宏示例

#define LOG(fmt, ...) \
    printf("[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)

int main() {
    LOG("Value = %d", 42);
    // 輸出:[main.c:10] Value = 42
    return 0;
}

六、最佳實踐總結

  1. 宏名全大寫,複雜宏用 do { ... } while(0) 包裹成語句塊
  2. 參數與表達式雙重加括號:#define MUL(a,b) ((a)*(b))
  3. 避免宏副作用:SQUARE(i++) 會導致 i 增加兩次
  4. 優先使用 inline 函數或 constexpr(C++)替代宏
  5. 條件編譯控制平台差異、調試開關、版本裁剪
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved