有时候,我更想念以前编写BASIC和汇编的时代。
我相信有很多人用C语言写了如下程序:
int main()
{
return 0;
}
然后编译成xxx.exe文件,然后用反编译软件(OD)打开查看:(结果因编译器不同而不同)
... ...
00401A10 . 56 push esi
00401A11 . 53 push ebx ; zero.00401A10
00401A12 . 83EC 14 sub esp,0x14
00401A15 . 833D 64704000>cmp dword ptr ds:[0x407064],0x2
00401A1C . 8B4424 24 mov eax,dword ptr ss:[esp+0x24] ; zero.00401A10
00401A20 . 74 0A je short zero.00401A2C
00401A22 . C705 64704000>mov dword ptr ds:[0x407064],0x2
00401A2C > 83F8 02 cmp eax,0x2
00401A2F . 74 12 je short zero.00401A43
00401A31 . 83F8 01 cmp eax,0x1
00401A34 . 74 3F je short zero.00401A75
00401A36 > 83C4 14 add esp,0x14
00401A39 . B8 01000000 mov eax,0x1
00401A3E . 5B pop ebx ; ntdll_12.779F9264
00401A3F . 5E pop esi ; ntdll_12.779F9264
00401A40 . C2 0C00 retn 0xC
00401A43 > BE 14904000 mov esi,zero.00409014
00401A48 . 81EE 14904000 sub esi,zero.00409014
00401A4E . 83FE 03 cmp esi,0x3
00401A51 .^ 7E E3 jle short zero.00401A36
00401A53 . 31DB xor ebx,ebx ; zero.00401A10
00401A55 > 8B83 14904000 mov eax,dword ptr ds:[ebx+0x409014]
00401A5B . 85C0 test eax,eax
00401A5D . 74 02 je short zero.00401A61
00401A5F . FFD0 call eax
00401A61 > 83C3 04 add ebx,0x4
00401A64 . 39DE cmp esi,ebx ; zero.00401A10
00401A66 .^ 75 ED jnz short zero.00401A55
00401A68 . 83C4 14 add esp,0x14
00401A6B . B8 01000000 mov eax,0x1
00401A70 . 5B pop ebx ; ntdll_12.779F9264
00401A71 . 5E pop esi ; ntdll_12.779F9264
00401A72 . C2 0C00 retn 0xC
00401A75 > 8B4424 28 mov eax,dword ptr ss:[esp+0x28] ; zero.00400000
... ...
这是什么鬼东西
好吧,所以说无论你编写怎样的代码,最后也将变成无数行汇编,那为何不直接写汇编呢?那是因为。。。我们懒嘛!
高级语言的好处在这里就可以体现出来:可读性! 但是随之而来的还有大量冗余的指令 <stdio.h> 中的printf()函数就有上千条指令,虽然说这多余的部分可以使该软件运行在其他的操作系统平台上,增加兼容性,但是这对我们真正了解电脑的工作原理没有好处。在软件运行中的很多问题bug是只有去查看反汇编才能体会的。
比如说:
#include<stdio.h>
int main()
{
int a=0,b;
b=(++a)+(++a)+(++a);
printf("%d\n",b);
return 0;
}
这段代码的运行结果是什么?
结果是不确定的,取决于你使用哪种编译器。如果你用gcc来编译的话,应该是输出:7 用VC编译输出: 9
(发生了什么?)
我们一般认为程序是这样运行的:a++;b+=a;a++;b+=a;a++;b+=a;所以应该输出b=1+2+3=6才对
(大家可以用反汇编查看,但考虑到不一定大家都看得懂,所以就不直接放出来了)
然而事实上依据从左向右的顺序, 相当于b=((++a)+(++a))+(++a)
b=(a+(++a))+(++a) //第一次脱括号的结果, 这时a=1
b=(a+a)+(++a) //第二次脱括号的结果. 这时a=2
b=(2+2)+(++a)
b=4+(++a) //第三次脱括号的结果, 这时a=2
b=4+a //第四次脱括号的结果, 这时a=3
b=4+3=7
//题外话:++a 在c++中是左值表达式, 但在c中不是左值表达式
在VC中是这样的:
a++;a++;a++;
b=a+a+a=9
可以看出其中的区别
所以在学习高级语言的时候,有必要了解一下软件底层的实现,而不是成为“码农”。