预处理

绍GNU C预处理器cpp,它是整个GCC的一部分。预处理器在源文件被编译以前展开其中的宏。它是由GCC在处理C或C++程序时被自动调用的。

定义宏
下面的程序演示了C预处理器最常用的用法,它用预处理器条件命令#ifdef来检查某个宏是否定义了。
当该宏被定义时,预处理器把直到#endif命令的相应代码包括入源文件。在该例中,被检查的宏被称为TEST,源代码中的条件部分是一行打印消息“Test mode”的printf声明:
#include
int
main (void)
{
#ifdef TEST
printf ("Test mode/n");
#endif
printf ("Running.../n");
return 0;
}
gcc的“-DNAME”选项在命令行上定义预处理宏NAME。如果上面的程序用带“-DTEST”命令行选项来编译,TEST宏将被定义,生成的可执行文件会打印两行消息:
$ gcc -Wall -DTEST dtest.c
$ ./a.out
Test mode
Running...
如果同样的程序不带“-D”选项来编译,则在经过预处理后,“Test mode”消息将从源代码中略掉,最后的可执行文件不会包括该行代码:
$ gcc -Wall dtest.c
$ ./a.out
Running...
宏通常都是未定义的除非用“-D”选项在命令行上指定,或在源文件中(或库的头文件)用#define定义。有些宏是由编译器自动定义的----这些宏会用到由双下划线(__)开始的保留的名字空间。
预定义的宏的完整列表可以这样得到,对某个空文件运行带“-dM”选项的GNU预处理器cpp:
$ cpp -dM /dev/null

预处理源文件
使用gcc的“-E”选项,你可以直接看到预处理器对源代码处理后的效果。例如,下面的文件定义并用到了宏TEST:
#define TEST "Hello, World!"
const char str[] = TEST;
如果该文件是“test.c”,则预处理后的效果可以用下面的命令看到:
$ gcc -E test.c
# 1 "test.c"
const char str[] = "Hello, World!" ;
“-E”选项导致gcc只运行预处理器,显示展开后的输出后,没有编译预处理过的源代码就退出了。TEST宏在输出中已经被替换,生成了字符序列const char str[] = "Hello, World!" ;。
预处理器也插入了一些行,以# line-number "source-file"的形式记录源文件和行数,有助于调试,允许编译器参考这些信息来报错。这些行并不会影响程序本身。
能够查看预处理过的源文件有助于检查include系统头文件的效果和查询系统函数的声明。下面的程序包括了头文件“stdio.h”,以便获得printf函数的声明:

#include

int
main (void)
{
printf ("Hello, world!/n");
return 0;
}
通过对要预处理的文件使用gcc –E,我们就能从被包括入的头文件中看到函数的声明:
$ gcc -E hello.c
在GNU系统上,输出可能象下面一样:
# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3
extern FILE

*stdin;
extern FILE *stdout;
extern FILE *stderr;
extern int fprintf (FILE * __stream,
const char * __format, ...) ;
extern int printf (const char * __format, ...) ;
[ ... 另外的声明 ... ]
# 1 "hello.c" 2
int
main (void)
{
printf ("Hello, world!/n");
return 0;
}
被预处理过的系统头文件通常产生许多输出。它们可以被重定向到文件中,或者更方便的是使用gcc的“-save-temps”选项来保存:
$ gcc -c -save-temps hello.c
运行该命令以后,预处理过的输出将被存储在文件“hello.i”中。“-save-temps” 选项除了保存预处理过的“.i”文件外,还会保存“.s”的汇编文件和“.o”的对象文件。

带调试信息编译
通常,可执行文件并不包含原来程序中源代码的任何引用信息,比如象变量名或行号----可执行文件只是编译器生成的作为机器码的指令序列。如果程序崩溃了,由于没有简便的方法找到错误的原因,所以这对调试是不够的。
GCC提供了“-g”调试选项来在对象文件和可执行文件中存储另外的调试信息。这些调试信息可以使得在追踪错误时能从特定的机器码指令对应到源代码文件中的行。它也可以使得该程序能被象gdb之类的调试器追踪调试(更多信息请见【进一步阅读】的“Debugging with GDB:The GNU Source-Level Debugger”)。使用调试器可以在程序运行时检查变量的值。
调试器是通过把函数名和变量(和所有对它们的引用),以及它们相应的原代码的行号存储到对象文件和可执行文件的符号表中来工作的。

检查core文件
“-g”选项除了允许程序在调试器控制下运行以外,另一个有用的应用是找到程序崩溃的环境。
当一个程序异常退出时,操作系统会写一个常规被称为“core”的文件,它包括了程序在崩溃刹那间的内存状态。结合由“-g”选项生成的符号表中的信息,程序员从core文件中可以查询到程序在哪一行停止了,和在那时候的变量的值。
这在软件开发期间和部署以后都是很有用的----它允许当程序在“某处”崩溃时能对问题展开调查。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值