|  | 
 
 发表于 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无止境,以共勉!
 | 
 |