LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1778|回复: 17

探讨一个scanf问题

[复制链接]
发表于 2009-1-31 05:44:40 | 显示全部楼层 |阅读模式
gcc得不到想要的结果。
#include <stdio.h>
int main(void)
{
  int c, rc;
  rc = scanf("%c", &c);
  int i=-1;
  printf("%d, %c", c , c);
  return 0;
}
gentoo的gcc 4.1和4。3版本都输出了不应该的结果。在一个debian的机器上,4。2。3版本,结果同样。但是在一个ubuntu的机器上,用的是4。3。2版本,输出了预期的结果,百思不得其解。如果把int i=-1(最可靠的办法就是初始化c);这行给去掉,就可以得到预期的结果(如果在x86_64编译器上用-m32编译32bit版本,结果也有问题)。
看起来是,[color="Red"]是scanf函数不允许(把char型,输入到int型)?但是为什么有的gcc版本可以呢?为什么  int i=-1;会干扰输出?
发表于 2009-1-31 06:57:45 | 显示全部楼层
不应该的结果啥样子?

那行打印语句应为

  1. printf("%d, %c", c&0xff , c);
复制代码

因为只读了一个字符,所以前三个字节都是垃圾。跟变量 i 没关系。
回复 支持 反对

使用道具 举报

发表于 2009-1-31 06:58:39 | 显示全部楼层
标准没有规定的行為是不确定的
就像 int a, b = 0;
a = b++ + ++b + b++;
一样
没有标准答案或者预期结果
回复 支持 反对

使用道具 举报

 楼主| 发表于 2009-1-31 08:57:20 | 显示全部楼层
这个程序是从一个书上的几十行的例子来的。发现有问题,调试到最后调试的结果就是上面的例子了。我可以理解认为c有部分字节没有初始化,如果初始化了,就没有这个问题了。[color="Red"]但是问题是为什么后的int i=-1;会对结果产生干扰?,有和没有结果不一样?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2009-1-31 09:00:37 | 显示全部楼层
Post by 8pm;1942482
标准没有规定的行為是不确定的
就像 int a, b = 0;
a = b++ + ++b + b++;
一样
没有标准答案或者预期结果

这个仅仅是编译器依赖,对同一个编译器结果是肯定的。
回复 支持 反对

使用道具 举报

发表于 2009-1-31 09:29:57 | 显示全部楼层
Post by blackwhite;1942488
这个仅仅是编译器依赖,对同一个编译器结果是肯定的。

Post by blackwhite;1942487
这个程序是从一个书上的几十行的例子来的。发现有问题,调试到最后调试的结果就是上面的例子了。我可以理解认为c有部分字节没有初始化,如果初始化了,就没有这个问题了。[color="Red"]但是问题是为什么后的int i=-1;会对结果产生干扰?,有和没有结果不一样?

虽然 C99 可以让你用之前才定义变量,但是标准没规定具体编译器怎么实现
例如是否需要一早就预留位置
在这个例子,用 -S 编译成汇编就可以看出那里不一样,leaq        -8(%rbp), %rsi,和 leaq        -12(%rbp), %rsi 的区别。
但是标准没定义,GCC 也没有承诺一定会这样实现。

所以我还是那句话,标准没规定的东西,没有肯定的结果。即便是你说的所謂的“编译器依赖”,不能保证一样结果就没有深究的必要
回复 支持 反对

使用道具 举报

 楼主| 发表于 2009-1-31 11:22:58 | 显示全部楼层
谢谢指教。汇编那里没有看明白(因为不懂)。
回复 支持 反对

使用道具 举报

发表于 2009-1-31 11:47:00 | 显示全部楼层
c没有初始化,你就不能预期当你只写入了它的一个字节之后剩下那三个字节是什么,如果编译器觉得舒服它便可以:如果你初始化i那么那三个字节就是0xffffff如果你没有初始化i那么那三个字节是0x000000(当然编译器也可以有任意的其他选择就是举个例子)
回复 支持 反对

使用道具 举报

发表于 2009-1-31 12:01:41 | 显示全部楼层
Post by blackwhite;1942509
谢谢指教。汇编那里没有看明白(因为不懂)。

不敢不敢,讨论而已,如果有不恰当的言语,还望多包涵。

leaq 指令就是 lea 指令的 64-bit 版(我用的是 x86_64)
回复 支持 反对

使用道具 举报

发表于 2009-1-31 12:27:21 | 显示全部楼层
Post by blackwhite;1942488
这个仅仅是编译器依赖,对同一个编译器结果是肯定的。

不一定是编译器依赖,scanf的%参数和后面给的指针必须严格一致,否则结果是不可预知的。具体的处理方式也可能是看库函数,当然编译器有可能把类似的函数直接转换成指令,这时就变成了编译器依赖了,否则就是标准库依赖而不是编译器依赖。

违反函数对参数的要求去调用函数,并依赖其“正确”结果本来就是撞大运,测试其在不同编译器下的结果对于学习语言确实有研究价值,但在实用中根本不应当这样写程序。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表