__FILE__、__LINE__ 實現精準調試定位當編譯器報錯 test.c:13: error: ... 時,它是如何獲取文件名和行號的?答案就是 C 語言標準定義的內置預定義宏。這些宏無需 #define,直接可用,在預處理階段展開為當前編譯上下文的常量值。
| 宏名 | 含義 | 類型 | 典型用途 |
|---|---|---|---|
__FILE__ | 當前源文件名 (含路徑) | 字符串常量 | 日誌、錯誤定位、斷言 |
__LINE__ | 當前行號 | 整數常量 | 同上 |
__DATE__ | 編譯日期 "Mmm dd yyyy" | 字符串 | 版本信息、構建時間戳 |
__TIME__ | 編譯時間 "hh:mm:ss" | 字符串 | 同上 |
__func__ / __FUNCTION__ | 當前函數名 (C99 標準 / GCC 擴展) | 字符串 | 函數級日誌追蹤 |
__STDC__ | 是否符合 ANSI C 標準 (1/0) | 整數 | 編譯器特性檢測 |
#include <stdio.h>
// 封裝調試宏:自動包含文件、行號、函數名
#define DEBUG_LOG(fmt, ...) \
printf("[DEBUG] %s:%d %s() " fmt "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
int show() {
DEBUG_LOG("Enter show()");
printf("hello\n");
DEBUG_LOG("Leave show()");
return 0;
}
int main() {
DEBUG_LOG("Program start");
show();
DEBUG_LOG("Program end");
return 0;
}
[DEBUG] test.c:15 main() Program start [DEBUG] test.c:8 show() Enter show() hello [DEBUG] test.c:11 show() Leave show() [DEBUG] test.c:18 main() Program end
#define MY_ASSERT(cond) \
do { \
if (!(cond)) { \
fprintf(stderr, "ASSERT FAILED: %s:%d %s() - '%s'\n", \
__FILE__, __LINE__, __func__, #cond); \
abort(); \
} \
} while(0)
#define MALLOC(size) my_malloc(size, __FILE__, __LINE__)
void* my_malloc(size_t size, const char *file, int line) {
void *p = malloc(size);
printf("[ALLOC] %p size=%zu at %s:%d\n", p, size, file, line);
return p;
}
在崩潰處打印 __FILE__、__LINE__,結合編譯時 -g 生成的調試信息,可快速定位源碼位置。
__func__ 是 C99 標準變量 (靜態字符數組),__FUNCTION__ 是 GCC/MSVC 擴展,建議用 __func__ 保證可移植性。# 可將宏參數變為字符串 (如 #cond → "cond")。## 可拼接 Token。內置宏是 C 語言「編譯期感知運行上下文」的少數機制之一。善用 __FILE__、__LINE__、__func__ 封裝統一的日誌/斷言/追蹤宏,能將調試效率提升數倍,是從「寫代碼」進階為「工程化開發」的標誌性技能。