阅读源码时有很多的条件编译语句,看起来不爽,怎么办?

    有些C程序,在编写的时候,为了应对多种情况(比如说支持多平台,选择某些特性等) ,就在源码当中使用了很多的宏来控制。当某些宏打开的时候某些代码才生效。如果代码当中,这些宏比较少,那还没什么,但是当代码当中有极多的宏的时候,阅读起来就很头疼了。如果有朋友看过QEMU的源码,会深有同感的。它的源码当中定义了很多的宏,有些函数针对某个平台的代码并不长,但是为了支持多平台,它就要定义不同的宏来控制在不同平台上对应的代码起作用。这对编译器是好事,但是如果我们只想看某个平台相关的代码就很麻烦了,以前很是苦恼,找不到很好的解决这个问题的办法。
    最近在用GCC的时候,发现其中的一些命令选项可以帮助我解决这个问题。基本的思想是让GCC在编译的时候不删除临时文件,而这些临时文件就包含了经过预处理之后的代码,这时候就不会有宏的干扰了,但是也失去了宏原本的意义(比如说某些常量,使用宏的话,可以见名知义)。举个例子来说,我们有这么一个C程序a.c
#include  < stdio.h >
int  main( int  argc,  char   * argv[])
{
    
int arch;
#ifdef _I386_
    arch 
= 1;
#elif _MIPS_
    arch 
= 2;
#elif _ARM_
    arch 
= 3;
#else
#error "Give me a architecture select!"
#endif
    
return 0;
}

    如果我们输入命令: $ gcc -D_MIPS_  -save-temps a.c
    这时候-save-temps选项告诉gcc在编译的过程中不要删除临时文件,那么在当前文件夹下就会产生:
1)a.i : 是经过C预处理程序(CPP)处理之后的文件,这个就是我们以后工作的基础
2)a.s: 是经过汇编器处理之后产生的汇编代码
3)a.o: 是编译器产生的目标代码
4)a.out: 是编译器默认产生的可执行程序。
    我们主要在a.i的上面进行操作,如果我们想看MIPS平台相关的代码,我们就使用上面的命令产生a.i,我们来看a.i的内容, 由于内容比较多,我这里只给出前10行和主体代码部分:
1   " a.c "
1   " <built-in> "
1   " <command line> "
1   " a.c "
1   " /usr/include/stdio.h "   1   3   4
28   " /usr/include/stdio.h "   3   4
1   " /usr/include/features.h "   1   3   4
329   " /usr/include/features.h "   3   4
1   " /usr/include/sys/cdefs.h "   1   3   4
313   " /usr/include/sys/cdefs.h "   3   4

...............................

850   " /usr/include/stdio.h "   3   4

2   " a.c "   2
int  main( int  argc,  char   * argv[])
{
    
int arch;



    arch 
= 2;





    
return 0;
}
    可以看出来,文件的内容基本是这么几个组成部分:
1) #include 语句会被扩展开来,并把对应内容包含进来,同时加入 “# _line_number "_include_file_name_
" xx xx" 这些信息
2) 源文件当中的信息会有所保留,宏被展开,注释被换成空行。条件宏起作用,其所在的行被换成空行。
    我们要做的就是把这些以#号开头的行和所有空行删除,并重新对a.i文件进行排版,那么它成了一个我们希望要的经过宏展开之后的C文件。
    如果文件数目不多,我们可以使用这个命令 $ gcc -D_MIPS_ -E -P a.c >t.c 来实现上述功能,这个命令就是告诉GCC只进行预编译,并且在预编译的时候不产生“#include"语句和一些不必要的空行。但是当文件很多,特别是我们使用Makefile文件来控制我们整个工程的编译的时候,这个方法就不合适了,就需要使用我前面提到的第
一种方法,具体做法如下:
1) 在Makfile文件当中的CFLAGS定义你想要的宏,并加上-save-temps选项,对于我们这个例子,我们可以定义: CFLAGS +=-D_MIPS -save-temps,然后执行make命令。执行成功之后,会生成一堆的 .i文件,下一步我么要操作.i文件。
2)执行这么一个脚本,它的作用就是把当前目录下的所有以.i作为后缀名的文件当中的 “#include" 行和空行删除。
# !/bin/bash
#filename: clearify.sh

for  f in  ./*. i
do
    name
= `basename  $f `
    sed 
" /^[[:space:]]*$/d "   $name   > t1
    sed 
" /^# .*$/d "  t1  > $name
done
如果你觉得文件排版不好看,还可以使用 $ indent  -kr  file_name 来进行美化排版。

希望对大家阅读含有很多宏的源码时有所帮助。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值