井号--数字--文件名
最近研究Lighttpd的源代码,发现代码中有很多宏定义,不直观,而且有的相当晦涩难懂。对付宏定义,其实有个偷懒的方法就是使用GCC的预编译机制,将它们展开,保存展开后的源代码,这样读起来就清晰多了。说白了就是使用gcc -E命令。
比如有个源代码文件google.c,内容如下:
struct sttest { int a; }; int main() { #define INIT_STRUCT(st, value) st.a = value struct sttest st1 , st2; INIT_STRUCT(st1, 4); INIT_STRUCT(st2, 5); return 0; }
使用gcc命令得到展开后等价的源代码:gcc -E google.c > google_ext.c。google_ext.c文件内容如下:
# 1 "google.c" # 1 "<built-in>" # 1 "<command line>" # 1 "google.c" struct sttest { int a; }; int main() { struct sttest st1 , st2; st1.a = 4; st2.a = 5; return 0; }
显而易见原来宏定义:INIT_STRUCT(st1,4);,已经被等价展开,这样读起来岂不是要易懂的多了?!不过,我也发现了个问题,就是# 1 "google.c"这种代码啥意思?看起来挺怪的。
对此做个小试验,编写测试代码如下:
#include <stdio.h> int main() { printf("A:%s>>%s>>%d\n", __FILE__, __FUNCTION__, __LINE__); //源文件行号:5 # 100 printf("B:%s>>%s>>%d\n", __FILE__, __FUNCTION__, __LINE__); //源文件行号:7 # 1000 printf("C:%s>>%s>>%d\n", __FILE__, __FUNCTION__, __LINE__); //源文件行号:9 printf("D:%s>>%s>>%d\n", __FILE__, __FUNCTION__, __LINE__); //源文件行号:10 # 10000 "new_file_name.c" printf("E:%s>>%s>>%d\n", __FILE__, __FUNCTION__, __LINE__); //源文件行号:12 printf("F:%s>>%s>>%d\n", __FILE__, __FUNCTION__, __LINE__); //源文件行号:13 return 0; }
将代码保存为test.c,编译执行,程序输出如下:
A:test.c>>main>>5
B:test.c>>main>>100
C:test.c>>main>>1001
D:test.c>>main>>1003
E:new_file_name.c>>main>>10000
F:new_file_name.c>>main>>10001
至此我们可以得出一个结论,像# 1 "google.c"这种伪代码的作用就是,标示紧跟其后一行代码的行号和文件名,并且对其后所有行均起作用,使得所有行都以该数字为基准重新编号。