GCC 上的预定义宏

 在标准C以及各中编译器中定义了一些对象宏, 这些宏的名称以"__"开头和结尾, 并且都是大写字符. 这些预定义宏可以被#undef, 也可以被重定义。

      在ANSI C标准中定义了__FILE__,__LINE__,__DATA__,__TIME__,__STDC__等标准的预定义宏。GCC对其进行扩展,也定义了多个预定义宏。

 

      概括起来GCC中可使用的预定义宏涵盖了如下几方面的信息:
      1、宿主的信息:GNU的版本,编译器的版本,类型的相关信息,字节序信息等。
      2、编译动作的信息:编译的日期、时间;编译时是否进行了时间或空间上的优化;定义的inline是否被编译器执行等。
      3、文件的信息:文件名称、函数名称、行数信息、文件最后修改时间等等。
      4、计数信息:__COUNTER__,__INCLUDE_LEVEL__等。

 

      下面是一些常见的预定义宏的使用方法。

 

1、__FILE__,__LINE__,FUNCTION__
      这是最常用到的预定义宏的组合,表示文件名、行数和函数名,用于程序运行期异常的跟踪。如:

       

[cpp]  view plain copy
  1. //-------file main.c----------  
  2. #include <stdio.h>  
  3. #include "myassert.h"  
  4.   
  5. int func(const char *filename);  
  6.   
  7. int main(int argc,char **argv)  
  8. {  
  9.     MyAssert("two args are needed",argc==2);  
  10.     func(argv[1]);  
  11.     return 0;  
  12. }  
  13.   
  14.   
  15. //-------file func.c----------  
  16. #include <sys/types.h>  
  17. #include <sys/stat.h>  
  18. #include <fcntl.h>  
  19. #include <unistd.h>  
  20. #include "myassert.h"  
  21.   
  22. int func(const char *filename)  
  23. {  
  24.     int fd;  
  25.     MyAssert("filename can not be null",filename);  
  26.     MyAssert("file not exist",0==access(filename,F_OK));  
  27.     fd = open(filename,O_RDONLY);  
  28.     close(fd);  
  29.     return 0;  
  30. }  
  31.   
  32.   
  33. //-------file myassert.h----------  
  34. #ifndef __MY_ASSERT_H__  
  35. #define __MY_ASSERT_H__  
  36.   
  37. #include <stdio.h>  
  38. #include <stdlib.h>  
  39.   
  40. #define  MyAssert(message,assertion) do{/  
  41.     if(!(assertion)){/  
  42.         printf("line %d in %s(%s)", __LINE__, __FILE__,__FUNCTION__);/  
  43.         if(message){/  
  44.             printf(" : %s",message);/  
  45.         }/  
  46.         printf("/n");/  
  47.         abort();/  
  48.     }/  
  49. }while(0);  
  50. #endif  
  51.   
  52. #Makefile  
  53. TARGET = test  
  54. CC = gcc  
  55. CCFLAGS = -Wall  
  56. OBJS = main.o func.o  
  57.   
  58. $(TARGET) : $(OBJS)  
  59.     $(CC) -o $@ $(OBJS) $(CCFLAGS)  
  60.   
  61. %.o : %.c  
  62.     $(CC) -o $@ -c $< $(CCFLAGS)  
  63.   
  64. clean:  
  65.     rm -rf *.o   
  66.     rm -rf $(TARGET)  

 

      运行./tset时:
      line 9 in main.c(main) : two argvs are needed
      Aborted

     

      运行./test kkk时:
      line 12 in func.c(func) : file not exist
      Aborted

 

      运行./test test时成功。

      可见通过使用__FILE__,__LINE__,FUNCTION__宏,可以帮助我们精确的定位出现异常的文件、函数和行数。

 

 

2、__BASE_FILE__

      这个宏是和__FILE__相对应的,表示主输入文件的名字,对于源文件而言__FILE__和__BASE_FILE__是一样的;对于头文件二者才可能不同。比如在上个例子中,__LINE__这个宏是在myassert.h文件中定义的,被main.c和func.c包含之后__FILE__的值
分别变成了main.c和func.c。但是当我们希望知道MyAssert这个宏具体实在哪个文件(实际上是myassert.h)中定义的话,就需要用到__BASE_FILE__。
     下面的例子可以帮助加深理解:

      

[cpp]  view plain copy
  1. //-------file main.c----------  
  2. #include <stdio.h>  
  3. #include "basefile.h"  
  4.   
  5. int main(int argc, char *argv[])  
  6. {  
  7.     printf("%s/n",sfile);  
  8.     printf("%s/n",hfile);  
  9.     return 0;  
  10. }  
  11.   
  12. //-------file basefile.h----------  
  13. const char sfile[]= __FILE__;  
  14. const char hfile[]= __BASE_FILE__;  
  

 

       gcc main.c &&./a.out 得到:

       basefile.h
       main.c

 

 3、__DATE__,__TIME__
       用于得到最后一次编译的日期和时间(字符串形式):

      

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. //-------file main.c----------  
  3. int main()  
  4. {  
  5.     printf("DATE : %s/n",__DATE__);  
  6.     printf("TIME : %s/n",__TIME__);  
  7. }  

 

       gcc main.c &&./a.out 得到:
       DATE : Jan 27 2011
       TIME : 17:12:55

 

4、__TIMESTAMP__
       和__TIME__的格式相同。同于得到本文件最后一次被修改的时间。

 

5、__GNUC__、__GNUC_MINOR__、__GNUC_MINOR__、__GNUC_PATCHLEVEL__
       用于得到GNU版本:

      

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. int main()  
  3. {  
  4.     if( __GNUC__ > 4 ||   
  5.         (__GNUC__ == 4 && (__GNUC_MINOR__ > 2 ||    
  6.             (__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ > 0)))){  
  7.         printf("GNUC version is later than 3.3.2/n");  
  8.     }else{  
  9.         printf("GNUC version is older than 3.3.2/n");  
  10.     }  
  11. }  

 

6、__VERSION__
     用于得到编译器的版本      

     

[cpp]  view plain copy
  1. //-------file main.c----------  
  2. #include <stdio.h>  
  3. int main()  
  4. {  
  5.     printf("Version : %s/n",__VERSION__);  
  6.     return 0;  
  7. }  

 

      gcc main.c && ./a.out得到:

      Version : 4.1.2 (Gentoo 4.1.2 p1.0.2)
      可以和gcc -v相互验证

 

7、__COUNTER__
      自身计数器,用于记录以前编译过程中出现的__COUNTER__的次数,从0开始计数。常用于构造一系列的变量名称,函数名称等。如:

     

[cpp]  view plain copy
  1. //-------file main.c----------  
  2. #include <stdio.h>  
  3.   
  4. #define FUNC2(x,y) x##y  
  5. #define FUNC1(x,y) FUNC2(x,y)    
  6. #define FUNC(x) FUNC1(x,__COUNTER__)  
  7.   
  8. int FUNC(var);  
  9. int FUNC(var);  
  10.   
  11. int main() {  
  12.     var0 = 0;  
  13.     var1 = 1;  
  14.     printf("%d/n",var0);  
  15.     printf("%d/n",var1);  
  16.     return 0;  
  17. }  

 

      gcc main.c &&a.out得到结果:
      0
      1
      这里使用__COUNTER__构造了两个变量:var0,var1。

8、__INCLUDE_LEVEL__
      用于表示文件被包含的计数,从0开始递增,常作为递归包含的限制条件。如:

     

[cpp]  view plain copy
  1. //-------file main.c----------  
  2. #include <stdio.h>  
  3. int main()  
  4. {  
  5.    #define REP_LIMIT 10  
  6.    #define REP(BLAH) printf("%d ", BLAH);  
  7.    #include "rep.h"  
  8.    printf("/n");  
  9.    return 0;  
  10. }  
  11.   
  12. //--------file rep.h----------  
  13. #if __INCLUDE_LEVEL__ < REP_LIMIT   
  14. REP(__INCLUDE_LEVEL__)  
  15. #include "rep.h"  
  16. #endif  

 

      gcc main.c && ./a.out,得到结果:
      1 2 3 4 5 6 7 8 9
      在这个例子中文件rep.h自包含了9次,执行了9次REP(BLAH)。

 

      实际上,__INCLUDE_LEVEL__最多的是和#include __FILE__组合使用,用于表示一个递归。如:

     

[cpp]  view plain copy
  1. //-------file main.c----------  
  2. #ifndef AUTOINC  
  3. #define AUTOINC  
  4.   
  5. #include <stdio.h>  
  6. #define MAX_LEVEL 10  
  7. int main()  
  8. {  
  9.     int i = 0;  
  10.     #include __FILE__  
  11.     printf("/n");  
  12.     return 0;  
  13. }  
  14. #undef AUTOINC  
  15. #endif  
  16.   
  17. #ifdef AUTOINC  
  18.     #if __INCLUDE_LEVEL__ <= MAX_LEVEL   
  19.     printf("%d ",__INCLUDE_LEVEL__);  
  20.     #include __FILE__  
  21.   
  22.     #if __INCLUDE_LEVEL__ != MAX_LEVEL  
  23.     printf("%d ",__INCLUDE_LEVEL__);  
  24.     #endif  
  25.   
  26.     #endif  
  27. #endif  

 

      gcc main.c && ./a.out得到结果:
      1 2 3 4 5 6 7 8 9 10 9 8 7 6 5 4 3 2 1

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值