|
发表于 2015-8-23 00:25:54
|
显示全部楼层
不得不说 楼主你问了一个相当纠结的问题,这里的#if #endif 只是跑堂而已, 关键问题是 后面while中的几句话,咋看 我们从简单的逻辑上面看 这几句话其实是没有太大的区别的,但是 这些语句的执行结果就是不一样,这里面问题到底在哪呢?
想不明白的情况下我只能通过C的反汇编工具将几种情况的While中的 比较都转化成了汇编代码,这样我还是用了不上时间最后终于是想明白了其中的道理;
下面看看汇编的代码(当然其中还有一部分关于C在编译成机器码的处理方式,这些都只能是我个人的假设,没有实际的依据):
while (k - m < 0)
001D7EE6 mov eax,dword ptr [k]
001D7EE9 sub eax,dword ptr [m]
001D7EEC jns main+89h (01D7F09h)
我们能看到此处的 减法结束后直接使用的跳转语句是 jns(s 代表sign 符号的意思):jns 飞负跳转
意思就是说 k-m的 结果如果是正数 那么就是说比0大也就是假 直接跳过while的循环代码;
这里我的 猜测是 在C 对 有符号整数结果与0 比较的时候 是直接 检测符号位是什么以确定是否执行循环;
while (m - k > 0)
001D7F09 mov eax,dword ptr [m]
001D7F0C sub eax,dword ptr [k]
001D7F0F test eax,eax
001D7F11 jle main+0AEh (01D7F2Eh)
这里的减法之后 有多出一句 test(结果为0 则 零标志位位1) 那么 jle(l 表示less小于,e是 equal 等于)小于等于跳转
个人 觉得 在sub中能检测到 小于 然后使用 test 来确认零标志 跳转使用不一样
那么前面的只是基本东西 重点是后面的东西
while ((m - strlen(p))>0)
001D7F2E mov eax,dword ptr [p]
001D7F31 push eax
001D7F32 call _strlen (01D1159h)
001D7F37 add esp,4
001D7F3A mov ecx,dword ptr [m]
001D7F3D sub ecx,eax
001D7F3F je main+0DCh (01D7F5Ch)
while (strlen(p) - m < 0)
00C9536C mov eax,dword ptr [p]
00C9536F push eax
00C95370 call _strlen (0C91159h)
00C95375 add esp,4
00C95378 sub eax,dword ptr [m]
00C9537B jmp main+108h (0C95398h)
在这两段代码中 我们可以看出相同的是 他们都是先计算了 strlen(p),然后做减法但是他们的 跳转指令却是很诡异
第一句 大于0的 跳转是 je(等于零跳转)完全不考虑小于0 的部分
第二句 小于0的 跳转是jmp(强制跳转)这个更是奇葩 直接不管结果就跳,这是为什么呢?
最终我有做了最后的实验 然后我就悟了(不止是否有大神在这里已经知道结果了!),请看下面的代码:
while ((int)strlen(p) - m < 0)
00C95398 mov eax,dword ptr [p]
00C9539B push eax
00C9539C call _strlen (0C91159h)
00C953A1 add esp,4
00C953A4 sub eax,dword ptr [m]
00C953A7 jns main+134h (0C953C4h)
这里我只是将 strlen的结果转化为int型即有符号整数,结果结合第一句是一样的了,跳转使用了 jns非负跳转;
到这里我想所有的迷已近解开, 其中的 关键就在一 函数strlen 的返回值是 无符号整数 unsigned int ,
同时 无符号整数在和有符号整数共同计算的时候 会被隐式转化为 无符号整数,所以 后两次的计算完全
不考虑为负数的情况
{
unsigned int x, y;
x = 5;
y = 10;
x -= y;
}x 的结果是一个奇大的正整数。。。。。。,个人猜测 C的编译器 会根据我们的 判断语句的 类型和
比较的方式 自行选择不同的跳转判定方式,故此 这里是因为对 C的了解不够深刻而出现的错误;
最后多谢楼主的题目,这一次我对C的一些理解又更近了一步! -------C无止境,以共勉! |
|