而对于另一个不是以宏定义,而是以变量定义的程序:
[attach]41518[/attach]
运行的结果是:
[attach]41519[/attach]
我们可以看到,这两个程序的运行结果是一样的.但仅仅是结果一样而己.
接下来我们可以利用CPP命令来对程序进行展开,首先对precompile1.c展开,由于如果加入printf会引入库函数,因此我们将这两个函数的printf去掉再编译:
[attach]41520[/attach]
可以看到,在进行了预编译的程序中,实行上 a己经被2取代了,在程序的编译过程中,并没有所谓的a存在.
之后我们对其产生的编译后(但未链接,因为PC的链接过程中会产生别的信息,打印现来会一大堆,为了方便简单的讲解,我们使用编译后的可重定位文件进行讲解)进行信息的提取:
pubuntu@pubuntu:~/Desktop/precompile$ readelf -a precompile1.o
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 176 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 9
Section header string table index: 6
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 00000f 00 AX 0 0 4
[ 2] .data PROGBITS 00000000 000044 000000 00 WA 0 0 4
[ 3] .bss NOBITS 00000000 000044 000000 00 WA 0 0 4
[ 4] .comment PROGBITS 00000000 000044 000026 01 MS 0 0 1
[ 5] .note.GNU-stack PROGBITS 00000000 00006a 000000 00 0 0 1
[ 6] .shstrtab STRTAB 00000000 00006a 000045 00 0 0 1
[ 7] .symtab SYMTAB 00000000 000218 000080 10 8 7 4
[ 8] .strtab STRTAB 00000000 000298 000014 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
There are no section groups in this file.
There are no program headers in this file.
There are no relocations in this file.
There are no unwind sections in this file.
Symbol table '.symtab' contains 8 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS precompile1.c
2: 00000000 0 SECTION LOCAL DEFAULT 1
3: 00000000 0 SECTION LOCAL DEFAULT 2
4: 00000000 0 SECTION LOCAL DEFAULT 3
5: 00000000 0 SECTION LOCAL DEFAULT 5
6: 00000000 0 SECTION LOCAL DEFAULT 4
7: 00000000 15 FUNC GLOBAL DEFAULT 1 main
No version information found in this file.
可以从里面看到,并没有出现这个叫a的东西的存在.
相同的,我们对precompile2.c进行cpp指令的展开
[attach]41521[/attach]
可以看到,函数代码中,是有a这个变量的,而不是像在预处理中被替换成了2.之后我们也同样可以对其产生的可重定位文件precompile2.o读取它的一些符号信息:
pubuntu@pubuntu:~/Desktop/precompile$ readelf -a precompile2.o
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 188 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 10
Section header string table index: 7
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000034 000012 00 AX 0 0 4
[ 2] .rel.text REL 00000000 0002f4 000008 08 8 1 4
[ 3] .data PROGBITS 00000000 000048 000004 00 WA 0 0 4
[ 4] .bss NOBITS 00000000 00004c 000000 00 WA 0 0 4
[ 5] .comment PROGBITS 00000000 00004c 000026 01 MS 0 0 1
[ 6] .note.GNU-stack PROGBITS 00000000 000072 000000 00 0 0 1
[ 7] .shstrtab STRTAB 00000000 000072 000049 00 0 0 1
[ 8] .symtab SYMTAB 00000000 00024c 000090 10 9 7 4
[ 9] .strtab STRTAB 00000000 0002dc 000016 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
There are no section groups in this file.
There are no program headers in this file.
Relocation section '.rel.text' at offset 0x2f4 contains 1 entries:
Offset Info Type Sym.Value Sym. Name
00000007 00000701 R_386_32 00000000 a
There are no unwind sections in this file.
Symbol table '.symtab' contains 9 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 FILE LOCAL DEFAULT ABS precompile2.c
2: 00000000 0 SECTION LOCAL DEFAULT 1
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 00000000 0 SECTION LOCAL DEFAULT 6
6: 00000000 0 SECTION LOCAL DEFAULT 5
7: 00000000 4 OBJECT GLOBAL DEFAULT 3 a
8: 00000000 18 FUNC GLOBAL DEFAULT 1 main
No version information found in this file.
由此可以看出,这里出现了一个叫a的全局变量,它存在于数据段中,占了四个字节.
经过以上的两个程序的分析,就可以知道预编译实际是在程序没有进行编译之前,就对程序进行了处理.像楼主所提出的#if,以及#include都是这种情况. 作者: ysjynkpgmw 时间: 2013-3-6 22:08
接下来我们对#if做一个程序进行下分析:
#define a 5
void main()
{
int x;
#if a==5
x=5;
#else
x=10;
#endif
}
我们使用CPP指令进行展开,会得到什么呢:
[attach]41522[/attach]
可以看到,x被直接赋值给了5.
接下来,我们对这个程序进行下改造:
int a=5;
void main()
{
int x;
#if a==5
x=5;
#else
x=10;
#endif
}
我们使用变量来试图对程序进行影响,之后我们用cpp指令进行展开:
[attach]41523[/attach]
但是出现的结果是,x被赋值了10.这是为什么呢?
原因是预处理命令是在程序还没有编译之前的操作,此时程序并没有a这个东西,所以更不会出现所谓的比较,实际上程序在预处理的时候,是计算#if后的表达式的值,而此时表达式是:
a==5
由于a此时是不存在的,也就是undef的,所以undef ==5的值计算出来是0,所以说,就会走到#else分支.
由此,可以从这点来讲楼主的问题了:
[attach]41525[/attach]
#if后面的一整行都会作为一个表达式来求值.那么
(CARD) i=8;这个表达式的值是多少呢?
很可惜,这个表达式C编译器无法计算,所以自然也就通不过了.
但当你分开后
[attach]41526[/attach]
#if表达式是
(CARD)
如果
#define CARD 1
那么就会i=8;
如果
#define CARD 0
就会走 i=4;
如果啥也没写呢?
那就会走i=4
但如果你只写了一个 #define CARD呢?编译器会告诉你:
error: missing expression between '(' and ')'因为它也不知道CARD被定义成了什么东西.它只是知道它被定义了.