C语言函数实现的另类方法
在前面看过那个BT的Javascript程序后,我们来看一个C语言的,相信大家还记得输出从1到1000的数最后的那个示例,本站还有很多这样的示例,如:变态的hello word,如何教新手编程,还有恐怖的C++,在下面这个示例面前,神马都是浮云。
下面这个示例向你展示了如何写一个swap()函数(把两个值交换),这段代码在我的Linux下的 gcc v4.1.1下可以正确编译通过,连一个Warning都没有,而且可以正确工作。我能说什么?!C语言并不疯狂,疯狂的是程序员。
include <stdio.h>
void(swap)() = (void()()) "\x8b\x44\x24\x04\x8b\x5c\x24\x08\x8b\x00\x8b\x1b\x31\xc3\x31\xd8\x31\xc3\x8b\x4c\x24\x04\x89\x01\x8b\x4c\x24\x08\x89\x19\xc3";
int main(){ // works on GCC 3+4
int a = 37, b = 13;
swap(&a, &b);
printf("%d %d\n",a,b);
}
其实,这种用字符串来实现函数的方法,在原理上是很好理解的。
字符串就是一段内存空间,把一个字符串指针强转成函数指针,那么这个指针所指向的内容就是各种指令,因此,那堆乱七八糟的东西说白了就是汇编。8086的汇编。你可以使用ndisasm来看看。
ruby -e "print \"\x8b\x44\x24\x04\x8b\x5c\x24\x08\x8b\x00\x8b\x1b\x31\xc3\x31\xd8\x31\xc3\x8b\x4c\x24\x04\x89\x01\x8b\x4c\x24\x08\x89\x19\xc3\"" | ndisasm -u -
00000000 8B442404 mov eax,[esp+0x4] ; load pointers to two parameters into eax, ebx
00000004 8B5C2408 mov ebx,[esp+0x8]
00000008 8B00 mov eax,[eax] ; load values of two parameters from pointers (eax, ebx) into eax, ebx
0000000A 8B1B mov ebx,[ebx]
0000000C 31C3 xor ebx,eax ; swap two values (eax, ebx) using xor trick
0000000E 31D8 xor eax,ebx
00000010 31C3 xor ebx,eax
00000012 8B4C2404 mov ecx,[esp+0x4] ; load pointer to param 1 into ecx
00000016 8901 mov [ecx],eax ; store swapped value 1 (eax) into param 1 (*ecx)
00000018 8B4C2408 mov ecx,[esp+0x8] ; load pointer to param 2 into ecx
0000001C 8919 mov [ecx],ebx ; store swapped value 2 (ebx) into param 2 (*ecx)
0000001E C3 ret
注意:这段汇编中使用了XOR而不是引入第三个变量来完成了变量值的交换。
关于XOR的方式,参看下面的示例:
a = a^b;
b=a^b;
a=b^a;
或者更为简单的:
a^=b^=a^=b;
(全文完)
转载于酷壳CoolShell 无删改 仅以此纪念陈皓(左耳朵耗子)
初创公司,地点东莞,目前公司是 4 个人员,在网络上招聘个 5 年经验,统招的大专以上,能独立做项目的,靠谱的 JAVA 开发真不容易。待遇在 12-15 区间,六险一金,双休…
2012年的时候写过一篇叫《程序算法与人生选择》的文章,我用算法来类比如何做选择,说白了就是怎么去计算,但是并没有讲程序员可以发展的方向有哪些。 所以,就算是有这些所谓的方法论…
如题,对三星的 ai 功能比较馋,但是都说它外版系统按 sim 卡确定用户区域。只卡一插国外卡能解决问题吗? 个人经验是任意卡槽只要有中国卡就难办 外版系统用一张国内卡一张…