[轉] Linux C – gcc 預先定義的巨集 #define

出處:http://eeepage.info/gcc-marco-01/

1. __BASE_FILE__
完整的原始檔案路徑
2. __cplusplus
表示該檔案由 g++ 所編譯,當成 C++ 的檔案
3. __DATE__
編譯的日期
4. __TIME__
編譯的時間
5. __FILE__
原始檔名
6. __LINE__
所在行數
7. __VERSION__
gcc 版本
8. __func__
替代 __FUNCTION__,__FUNCTION__ 已被 GNU 不推薦使用
GCC提供三個能夠給出當前函數名的神奇變數,第一個變數是”__func__”,其是C99標準的一部分:
識別字”__func__”由轉譯器隱式聲明,就像函數定義的開始花括弧緊跟它的後面,其聲明如下
static const char __func__[] = “function-name”;
其中”function-name”即是函數的詞條名,此名尚未被變形。
“__FUNCTION__” 是”__func__”的一個別名。舊版本的GCC只認得這個名稱。然而,它還未被標準化,為了獲取最大可能的移植性推薦使用”__func__”代之,可通過預處理器宏提供向後相容:
#if __STDC_VERSION__ < 199901L
# if __GNUC__ >= 2
# define __func__ __FUNCTION__
# else
# define __func__ “”
# endif
#endif
在C中,”__PRETTY_FUNCTION__”也是”__func__”的另一個別名。然而,在C++中,除了包含函數裸名外,還包含函數簽名。例如,看下麵的程式:
extern “C” {
extern int printf (char *, …);
}
class a {
public:
void sub (int i)
{
printf (“__FUNCTION__ = %sn”, __FUNCTION__);
printf (“__PRETTY_FUNCTION__ = %sn”, __PRETTY_FUNCTION__);
}
};
int main (void)
{
a ax;
ax.sub (0);
return 0;
}
產生如下的輸出:
__FUNCTION__ = sub
__PRETTY_FUNCTION__ = void a::sub(int)
這些識別字並非預處理器宏。在GCC 3.3和早期版本中,僅限於C中”__FUNCTION__”和”__PRETTY_FUNCTION__”被作為字面量,它們可被用於初始化字元陣列, 也可與其他字串相連接。GCC 3.4和後來版本,像”__func”一樣將它們作為變數。在C++中,”__FUNCTION__”和 “__PRETTY_FUNCTION__”總被作為變數。
reference: http://jyhshin.pixnet.net/blog/post/26588145

===================================================================

宏的高级使用–##,__VA_ARGS__, __FILE__, __FUNCTION__等

分类: 程序设计 Linux2012-08-10 11:23 1338人阅读 评论(1) 收藏 举报

先说一下本文中会提到的内容:##,__VA_ARGS__, __FILE__, __LINE__ , __FUNCTION__等
宏变量:
先举一个例子,会用到上面这些宏:

  1. #define myprintf(…) printk(“[lch]:File:%s, Line:%d, Function:%s,”   
  2.      __VA_ARGS__, __FILE__, __LINE__ ,__FUNCTION__);  

此处的 #define 的作用是将 myprintf( )换成后面那一大串的内容,而括号内 … 的内容原样抄写在 __VA_ARGS__ 的位置。最终输出如下:
[lch]:File:arch/arm/mach-omap2/board-omap3wscec-camera.c, Line:163, Function:beagle_cam_init,camera init!
解析:
1)__VA_ARGS__:总体来说就是将左边宏中 … 的内容原样抄写在右边 __VA_ARGS__ 所在的位置。它是一个可变参数的宏,是新的C99规范中新增的,目前似乎只有gcc支持(VC从VC2005开始支持)。要注意的是,printf 的输出格式是括号内左边是字符串,右边是变量,而且右变量与左输出格式是一一对应的。所以在上面那个例子中, __VA_ARGS__只能是一些不含任何变量的字符串常量。因为上面的例子中若__VA_ARGS__含有变量,整个printf的输出与变量便不能一一对应,输出会出错。
如果仅仅是替换函数名,可用如下方式,此时对__VA_ARGS__无任何特殊要求:#define myprintf(…) printk( __VA_ARGS__),在调试程序时可以这样用:

  1. #ifndef LOG_NDEBUG_FUNCTION  
  2. #define LOGFUNC(…) ((void)0)  
  3. #else  
  4. #define LOGFUNC(…) (printk(__VA_ARGS__))  
  5. #endif  

2) __FILE__ :宏在预编译时会替换成当前的源文件名
3) __LINE__:宏在预编译时会替换成当前的行号
4) __FUNCTION__:宏在预编译时会替换成当前的函数名称
5)类似的宏还有 __TIME__,__STDC__, __TIMESTAMP__等,就完全当一个变量来使用即可。

宏连接符##:
举个例子:宏定义为#define XNAME(n) x##n,代码为:XNAME(4),则在预编译时,宏发现XNAME(4)与XNAME(n)匹配,则令 n 为 4,然后将右边的n的内容也变为4,然后将整个XNAME(4)替换为 x##n,亦即 x4,故 最终结果为 XNAME(4) 变为 x4.
代码如下:

  1. #include <stdio.h>  
  2. #define XNAME(n) x ## n  
  3. #define PRINT_XN(n) printf(“x” #n ” = %d/n”, x ## n);  
  4. int main(void)  
  5. {  
  6. int XNAME(1) = 14; // becomes int x1 = 14;  
  7. int XNAME(2) = 20; // becomes int x2 = 20;  
  8. PRINT_XN(1); // becomes printf(“x1 = %d,”, x1);  
  9. PRINT_XN(2); // becomes printf(“x2 = %d/n”, x2);  
  10. return 0;  
  11. }  

输出为:x1 = 14, x2 = 20

PS:编译过程:
1,扫描解析文件
2,预处理(宏在此时处理,该替换的文字会被替换)
3,对处理过的源代码进行汇编,输出汇编语言的代码(C语言的控制流程被处理)
4,编译为二进制目标文件
5,与程序库进行链接,输出最终的程序文件
(宏 和 C语言在不同的阶段处理执行)

未經允許不得轉載:GoMCU » [轉] Linux C – gcc 預先定義的巨集 #define