把*****处,分别替换成下面#if() #endif
本帖最后由 haiouda 于 2015-4-1 12:17 编辑#include<stdio.h>
#include<string.h>
int main()
{
char * p="I love fishc.com!" ;
int m,k;
printf("input m:");
scanf("%d",&m);
k=strlen(p);
*****************
return 0;
}
#if(0)
while( k-m<0 )
{
printf("input m:");
scanf("%d",&m);
}
#endif
#if(0)
while( m-strlen(p)>0 )
{
printf("input m:");
scanf("%d",&m);
}
#endif
#if(0)
while( strlen(p)-m<0 )
{
printf("input m:");
scanf("%d",&m);
}
#endif
把第15行*****处,分别替换成下面#if() #endif 中内容,为何结果不同?
导电性heart 发表于 2015-4-1 15:09
把#if和#endif复制进去,0改1之后都是正常循环
我上面的程序只是其中的一段,你可以试着把下面几上分别复制进去,再一步步调试,才能发现问题的哟;
下面三个,#if(0) #endif 之间的内容在数学上是完全相等的,在程序里确出问题了,所以想不明白才在这里发贴子的。 把#if和#endif复制进去,0改1之后都是正常循环:lol: {:1_1:} {:1_1:} 本帖最后由 流行语 于 2015-4-3 17:39 编辑
#if(0)条件都不成立,怎么会运行呢,在C中非0即为true,否则为false。 流行语 发表于 2015-4-3 17:38
#if(0)条件都不成立,怎么会运行呢,在C中非0即为true,否则为false。
你不会,用哪个时,就把哪个打开呀 {:1_1:} 不得不说 楼主你问了一个相当纠结的问题,这里的#if #endif 只是跑堂而已, 关键问题是 后面while中的几句话,咋看 我们从简单的逻辑上面看 这几句话其实是没有太大的区别的,但是 这些语句的执行结果就是不一样,这里面问题到底在哪呢?
想不明白的情况下我只能通过C的反汇编工具将几种情况的While中的 比较都转化成了汇编代码,这样我还是用了不上时间最后终于是想明白了其中的道理;
下面看看汇编的代码(当然其中还有一部分关于C在编译成机器码的处理方式,这些都只能是我个人的假设,没有实际的依据):
while (k - m < 0)
001D7EE6mov eax,dword ptr
001D7EE9sub eax,dword ptr
001D7EECjns main+89h (01D7F09h)
我们能看到此处的 减法结束后直接使用的跳转语句是 jns(s 代表sign 符号的意思):jns 飞负跳转
意思就是说 k-m的 结果如果是正数 那么就是说比0大也就是假 直接跳过while的循环代码;
这里我的 猜测是 在C 对 有符号整数结果与0 比较的时候 是直接 检测符号位是什么以确定是否执行循环;
while (m - k > 0)
001D7F09mov eax,dword ptr
001D7F0Csub eax,dword ptr
001D7F0Ftest eax,eax
001D7F11jle main+0AEh (01D7F2Eh)
这里的减法之后 有多出一句 test(结果为0 则 零标志位位1) 那么 jle(l 表示less小于,e是 equal 等于)小于等于跳转
个人 觉得 在sub中能检测到 小于然后使用 test 来确认零标志 跳转使用不一样
那么前面的只是基本东西 重点是后面的东西
while ((m - strlen(p))>0)
001D7F2Emov eax,dword ptr
001D7F31push eax
001D7F32call _strlen (01D1159h)
001D7F37add esp,4
001D7F3Amov ecx,dword ptr
001D7F3Dsub ecx,eax
001D7F3Fje main+0DCh (01D7F5Ch)
while (strlen(p) - m < 0)
00C9536Cmov eax,dword ptr
00C9536Fpush eax
00C95370call _strlen (0C91159h)
00C95375add esp,4
00C95378sub eax,dword ptr
00C9537Bjmp main+108h (0C95398h)
在这两段代码中 我们可以看出相同的是 他们都是先计算了 strlen(p),然后做减法但是他们的 跳转指令却是很诡异
第一句 大于0的 跳转是 je(等于零跳转)完全不考虑小于0 的部分
第二句 小于0的 跳转是jmp(强制跳转)这个更是奇葩 直接不管结果就跳,这是为什么呢?
最终我有做了最后的实验 然后我就悟了(不止是否有大神在这里已经知道结果了!),请看下面的代码:
while ((int)strlen(p) - m < 0)
00C95398mov eax,dword ptr
00C9539Bpush eax
00C9539Ccall _strlen (0C91159h)
00C953A1add esp,4
00C953A4sub eax,dword ptr
00C953A7jns main+134h (0C953C4h)
这里我只是将 strlen的结果转化为int型即有符号整数,结果结合第一句是一样的了,跳转使用了 jns非负跳转;
到这里我想所有的迷已近解开, 其中的 关键就在一函数strlen 的返回值是 无符号整数 unsigned int ,
同时 无符号整数在和有符号整数共同计算的时候 会被隐式转化为 无符号整数,所以 后两次的计算完全
不考虑为负数的情况
{
unsigned int x, y;
x = 5;
y = 10;
x -= y;
}x 的结果是一个奇大的正整数。。。。。。,个人猜测 C的编译器 会根据我们的 判断语句的 类型和
比较的方式 自行选择不同的跳转判定方式,故此 这里是因为对 C的了解不够深刻而出现的错误;
最后多谢楼主的题目,这一次我对C的一些理解又更近了一步! -------C无止境,以共勉! {:7_121:} if(0)条件都不成立
页:
[1]