GCC 預定義宏:解鎖編譯器的隱藏信息
在 GCC 編譯器中,有許多內置的預定義宏,它們可以提供編譯環境的信息,如文件名、行號、時間、版本等。這些宏在調試、日志記錄、條件編譯等場景中非常有用。本文將介紹常見的 GCC 預定義宏,并提供示例代碼及其輸出結果。
1. 文件與函數信息宏
這些宏提供了代碼的文件名、行號、函數名等信息,常用于日志記錄和調試。
1.1 __FILE__
- 獲取當前源文件名
表示當前源文件的名稱(字符串)。
示例:
#include <stdio.h>int main() {printf("File: %s\n", __FILE__);return 0;
}
可能的輸出:
File: main.c
1.2 __LINE__
- 獲取當前行號
表示當前代碼的行號(整數)。
示例:
#include <stdio.h>int main() {printf("Line: %d\n", __LINE__);return 0;
}
可能的輸出:
Line: 4
(實際行號取決于代碼所在位置)
1.3 __FUNCTION__
/ __func__
- 獲取當前函數名
在 C99 及更高版本中,__FUNCTION__
和 __func__
都可以獲取當前函數的名稱,__func__
是更標準的寫法。
示例:
#include <stdio.h>void test() {printf("Function: %s\n", __func__);
}int main() {test();return 0;
}
可能的輸出:
Function: test
2. 編譯時間信息宏
這些宏提供編譯時的日期和時間,常用于生成版本信息或調試日志。
2.1 __DATE__
- 獲取編譯日期
格式:"Mmm dd yyyy"
,如 "Mar 21 2025"
示例:
#include <stdio.h>int main() {printf("Compiled on: %s\n", __DATE__);return 0;
}
可能的輸出:
Compiled on: Mar 21 2025
2.2 __TIME__
- 獲取編譯時間
格式:"hh:mm:ss"
,如 "21:30:00"
示例:
#include <stdio.h>int main() {printf("Compiled at: %s\n", __TIME__);return 0;
}
可能的輸出:
Compiled at: 21:30:00
3. 條件編譯相關宏
這些宏可用于檢查編譯器的特性、語言標準和目標平臺,以實現兼容性處理。
3.1 __STDC__
- 判斷是否為標準 C 編譯器
如果編譯器遵循 ANSI C 標準,則此宏定義為 1
。
示例:
#ifdef __STDC__printf("This is an ANSI C compiler\n");
#endif
3.2 __STDC_VERSION__
- 檢查 C 語言標準版本
表示 C 語言標準的版本號,例如:
199409L
(C90)199901L
(C99)201112L
(C11)201710L
(C17)
示例:
#if __STDC_VERSION__ >= 201112Lprintf("C11 or later is supported\n");
#endif
3.3 __cplusplus
- 檢查是否為 C++ 編譯
如果使用 C++ 編譯器,該宏會被定義,且值表示 C++ 標準的版本號,如:
199711L
(C++98)201103L
(C++11)201402L
(C++14)201703L
(C++17)
示例:
#ifdef __cplusplusprintf("This is a C++ compiler\n");
#endif
4. 編譯器與平臺信息宏
4.1 __GNUC__
- 檢查是否使用 GCC 編譯器
如果使用 GCC 編譯器,則此宏被定義,其值為 GCC 主版本號。
示例:
#ifdef __GNUC__printf("Compiled with GCC %d\n", __GNUC__);
#endif
可能的輸出(GCC 13.1 編譯時):
Compiled with GCC 13
4.2 __linux__
- 檢查是否在 Linux 上運行
如果目標系統是 Linux,則此宏被定義。
示例:
#ifdef __linux__printf("Running on Linux\n");
#endif
4.3 __x86_64__
- 檢查是否是 64 位架構
如果目標架構是 64 位 x86,則此宏被定義。
示例:
#ifdef __x86_64__printf("64-bit architecture\n");
#endif
5. 其他實用宏
5.1 __COUNTER__
- 遞增的唯一標識符
此宏從 0 開始,每次使用時加 1,常用于生成唯一變量名。
示例:
#include <stdio.h>#define UNIQUE_NAME(x) x##__COUNTER__int UNIQUE_NAME(var) = 10;
int UNIQUE_NAME(var) = 20;int main() {printf("Unique variables defined.\n");return 0;
}
編譯后變量名可能變為 var0
和 var1
,避免了名稱沖突。
5.2 __BASE_FILE__
- 獲取主編譯文件
如果某個文件是通過 #include
包含進來的,而不是直接編譯的源文件,那么 __FILE__
會顯示該文件名,而 __BASE_FILE__
會顯示實際的主編譯文件。
示例:
printf("Base file: %s\n", __BASE_FILE__);
6. 綜合示例:獲取編譯信息
#include <stdio.h>int main() {printf("File: %s\n", __FILE__);printf("Line: %d\n", __LINE__);printf("Compiled on: %s at %s\n", __DATE__, __TIME__);#ifdef __GNUC__printf("GCC version: %d.%d\n", __GNUC__, __GNUC_MINOR__);#endifreturn 0;
}
可能的輸出:
File: main.c
Line: 5
Compiled on: Mar 21 2025 at 21:30:00
GCC version: 13.1
7. 結論
這些 GCC 預定義宏在調試、日志、條件編譯等場景中非常實用。建議在編寫可移植代碼時,合理利用這些宏來增強代碼的靈活性和可讀性。