一个C语言printf输出的问题

导论

本文是我在segmentfault回复一个C语言printf输出的问题的答案,写完之后 发现写了这么长了,还是发到博客好了了。

问题

int main(int argc, const char * argv[]) {
printf("%g\n", (double)15/10 );//1.5
printf("%g\n", 25/(double)10 );//2.5
printf("%g\n", 35/10 );//2.5
printf("%g\n", (double)(45/10) );//4
return EXIT_SUCCESS;
}
int main(int argc, const char * argv[]) {
printf("%g\n", 35/10 );//0
return EXIT_SUCCESS;
}

请帮忙解释一下 35/10 的输出?

printf("%g\n", 3 );//0

前言

很高兴看到这样的问题,因为这涉及到现在的人们已经普遍不怎么关心的底层操作。 在人们看来,浮点数和整数就差了一个小数点,但在计算机看来,这里面差别缺非常之大。 这是因为他们的解析方式不同。

证明

int main(int argc, const char * argv[]) {
float i = 3;
printf("%08x\n", *(unsigned int*)&i);
unsigned int j = 3;
printf("%08x\n", *(unsigned int*)&j);
getchar();
return EXIT_SUCCESS;
}

这段代码用来输出内存中他们真正的值(十六进制)。 这两句的代码唯一的区别在于他们的类型不同,第一个为float,第二个为unsigned int。 在人类看来,他们几乎是一样的,但在内存中,他们完全不可混为一谈。 上面的输出结果为

40400000
00000003

即,浮点型的3在内存中为40400000,整数型的在内存中为3。 怎么样,他们的是不是不一样的?

延伸

int main(int argc, const char * argv[]) {
float i = 3;
printf("%g\n", i);
int j = 3;
printf("%g\n", j);
getchar();
return EXIT_SUCCESS;
}

那么你认为他们的结果会一致吗?当然不会。它的结果为:

3
2.55827e-303 //溢出,可能不一致

所以

在c语言中/运算符不会改变结果类型,也就是说,两个整数型相除的结果也是个整数型。

int main(int argc, const char * argv[]) {
printf("%g\n", 35 / 10);//0
getchar();
return EXIT_SUCCESS;
}

你的代码中就相当于

int main(int argc, const char * argv[]) {
printf("%g\n", 3);
getchar();
return EXIT_SUCCESS;
}

这当然不会是你期望的。

再次证明

要怎么证明呢?很简单,我们看下反汇编的代码就知道了

push ebp
mov ebp,esp
sub esp,0C0h
push ebx
push esi
push edi
lea edi,[ebp-0C0h]
mov ecx,30h
mov eax,0CCCCCCCCh
rep stos dword ptr es:[edi]
push 3 //此处传入的本来就是个常量 3
push offset string "%g\n" (0D23D20h)
call _printf (0D01F91h)
add esp,8
mov esi,esp
call dword ptr [__imp__getchar (0D2A3A0h)]
cmp esi,esp
call __RTC_CheckEsp (0D0161Dh)
xor eax,eax
pop edi
pop esi
pop ebx
add esp,0C0h
cmp ebp,esp
call __RTC_CheckEsp (0D0161Dh)
mov esp,ebp
pop ebp

修正

我们将上面的代码稍微改一下,只要让编译器认为我们输入的是个小数型就可以了。方法有很多种。

printf("%g\n", (double)15/10 );//1.5
printf("%g\n", 25/(double)10 );//2.5
printf("%g\n", 35/10+0.0 );//2.5
printf("%g\n", (double)(45/10) );//4

版权说明

本页地址为 https://post.zz173.com/detail/50620.html,本文作者为落月
本文采用 署名-相同方式共享 3.0 中国大陆许可协议 ,分享、演绎需署名且使用相同方式共享。转载请务必保留本页网址和作者信息,否则即为侵权。

– EOF –