【问题标题】:Type conversion in Printf [duplicate]Printf中的类型转换[重复]
【发布时间】:2013-11-22 05:39:12
【问题描述】:

代码sn-p的o/p:

printf("%f", 9/5);
  1. 在我的 linux gcc 4.6.3 中(gcc myprog.c 后跟 ./a.out):

    -0.000000

  2. 在 codepad.org 中:

    2.168831

为什么不一样?

我已经引用了链接:Why cast is needed in printf?Implicit conversion in C?,但无法使用它。

有关键盘执行的信息: C:GCC 4.1.2 标志:-O -fmessage-length=0 -fno-merge-constants -fstrict-aliasing -fstack-protector-all

编辑: 更多的: 用于在(在同一程序中)键盘中执行以下操作

printf("%f\n", 99/5);
printf("%f\n", 18/5);
printf("%f\n", 2/3);
printf("%f\n%f\n%f", 2, 3, 4);
printf("%f\n", 2);

o/p 是

2.168831
2.168831
2.168831
0.000000
0.000000
-0.001246
-0.0018760.000000

前三个输出是相同的垃圾值(而不是最后一个)。想知道为什么。

【问题讨论】:

  • GCC 4.4.7 产生:前 4 个 printfs 为 0.000000,最后一个为 0.0000000.000000。

标签: c gcc type-conversion printf


【解决方案1】:

9/5 被视为 int .. 当您使用格式说明符 %f 时会导致未定义的输出(需要双精度)

要打印正确的结果,请执行以下操作:

printf("%f", 9.0/5); // forces system to make sure that the argument is not treates as int

printf("%f\n",(double)9/5); // type casting the argument to a double .. this is more helpful 
                            // in case you have a variable

我不确定 codepad.org 是如何编译他们的代码的……但是对于 gcc,你必须有正确的参数才能使 printf 与格式说明符匹配


请仔细考虑以下内容:

#include <stdio.h>
int main(){ 
    printf("%f %d %f\n",9/5,9/5,9.0/5);
    printf("%f\n",1); // as suggested by devnull-again since the argument is not a double
                      // the output is undefined
    return 0;
}

输出:

$ ./test
0.000000 1 1.800000
0.000000

【讨论】:

  • 您可以通过修改示例以包含以下结果来使答案更完整:printf("%f\n", 1);
  • 感谢您的信息。我也添加了有关键盘如何编译的详细信息。
  • @Karthiprime 不客气......如果他们帮助了你,请接受答案
【解决方案2】:

这是未定义的行为,任何东西都可以打印。 9/5 的类型是 int%f 需要传递double(如果传递float,由于参数自动提升到可变参数函数调用,它将被转换为double,所以也可以)。

既然你不给双倍,任何事情都可能发生。

在实践中,假设sizeof(int)==4sizeof(double)==8,您的 printf 调用将读取 4 个字节的随机垃圾。如果这都是零,那么您将打印零。如果不是,你会打印随机的东西。

【讨论】:

  • printf 调用将读取 4 个字节的随机 garbase => 感谢您提供的信息。
  • @Mat - 恕我直言,你错了 - printf 将从堆栈中获取的内容由格式字符串确定,并且堆栈上的常规 int 被推送而不是加倍。
  • @Artur:我就是这么说的。当传递的所有内容都是 int 时,printf 将读取 double 的值。所以它会读取垃圾
  • @Mat:打印时不必全为零(意思是零)。 exponent=0 的所有内容都必须打印为零 - 如果不是 - 编译器不知道如何正确解释浮点。例如: printf("%f", 0x12340000); 必须按照标准打印 0.0,它必须被视为零。数以千计的其他模式也必须意味着零。
  • @Artur: printf("%f", 0x12340000); => 在 gcc 4.1.2 (codepad.org) 中执行将 o/p 抛出为 2.168831。有什么想法吗?
【解决方案3】:

键盘错误。 如果另有说明,每个数字都是 int - 这是解决方案的关键。

在 C/C++ 中,9/5 是整数,等于 1 这就是为什么你的:

printf("%f\n", 9 / 5);

等同于:

printf("%f\n", 1);

但是为什么它打印 0.0 你问 - 这就是为什么。 当 printf 被赋予 '%f' 标志时,它会将参数视为浮点数。

现在您的代码反汇编看起来/可能看起来像这样:

printf("%f\n", 9 / 5);
push        1    
call        dword ptr [__imp__printf (0B3740Ch)]

push 1 在堆栈上移动(通常是 32 位 0x1)

现在最重要的是 32 位 value=1 的外观(二进制):

(MSB) 00000000 00000000 00000000 00000001 (LSB)

如果将这种模式视为 32 位浮点数意味着什么(根据 this):

符号(第 31 位)= 0

指数(接下来的 8 位,即 #30..#23)也都 = 0

分数(其余位)包含 1(dec)

这是理论上但 exponent=0x0 是特殊情况(阅读 link)并被视为 0.0 - 句点。

【讨论】:

  • 使用反汇编的解释真的很有帮助。 @Mat 有更多信息。
  • 密码板没有错。当参数的类型与其格式说明符不匹配时,C 标准没有定义行为。期望 int 参数的字节将被解释为 floatdouble 是不正确的。
  • 恕我直言,这是完全正确的——“%f”格式说明符是为了让 printf 知道它应该如何处理堆栈上的值(如果使用了 cdecl)。 Printf 只是不知道堆栈上有什么 - 它必须信任用户。如果用户说“%f”,那么 printf 除了从堆栈中取出 4 个字节并将它们解释为浮点数之外,别无他法。如果它不能正确地将 4 字节模式解释为浮点数,那么这个特定的 printf 只是编码错误。并不是说我是 VC 的忠实粉丝,但 VC 的 printf 在问题中显示的所有情况下都可以正常工作。
  • @Artur:C 实现不需要使用堆栈来传递参数,也不需要在同一位置传递整数和浮点参数。此外,当参数的相应格式说明符的类型错误时,C 标准允许 any 行为。允许编译器观察不匹配并生成任何代码作为结果。
  • 此外,此答案中的数学将这些位解释为 32 位二进制浮点数,但 %f 用于 double,通常为 64 位。
猜你喜欢
  • 1970-01-01
  • 2014-08-17
  • 1970-01-01
  • 2016-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多