【问题标题】:strange output while printing float as integer and integer as float in C [duplicate]在C中将浮点数打印为整数和整数作为浮点数时出现奇怪的输出[重复]
【发布时间】:2014-08-27 19:29:29
【问题描述】:

以下代码没有显示预期的输出,即垃圾值(奇怪的是这些值被交换了)

#include<stdio.h>
int main()
{
    float f = 4.6;
    int d = 7;
    printf("%d %f\n",f,d);
    return 0;
}

输出: 7 4.600000

【问题讨论】:

  • 何不真的搞得一团糟:printf("%d %f\n",(int)f,(float)d);
  • 标准说:C11 7.21.6.1:“如果任何参数不是相应转换规范的正确类型,则行为未定义。
  • 所以不要那样做。当格式字符串是文字时,一些编译器(尤其是 gcc)可以警告 printf 的参数不匹配,但通常完全取决于您是否正确调用 printf
  • 那是哪个 ABI(处理器、编译器……)?我猜整数和浮点值在不同的寄存器中传递。
  • 如果您使用gcc -Wall -g 编译,您将收到一条警告消息,然后您将在几秒钟内改进错误的源代码。

标签: c output


【解决方案1】:

让我们减少一点:

float f = 4.6;
printf("%d\n", f);

这是未定义的行为。必须为正确的格式说明符提供正确类型的参数。

未定义的行为可能导致任何结果,包括您看到的这种奇怪的结果。

进一步的想法:

现在,您可能会问为什么编译器会生成这段代码。那么让我们看一下 x86-64 程序集的 2 个代码:

int main() {
    float f = 4.6;
    int d = 7;
    printf("%d %f\n", d, f);
    return 0;
}

int main() {
    float f = 4.6;
    int d = 7;
    printf("%f %d\n", f, d);
    return 0;
}

除了格式字符串,这两个代码产生相同的程序集。这可能是因为调用约定要求将浮点数放置在与整数不同的寄存器中,或者浮点数应在堆栈上传递(或任何数量的其他以不同方式处理浮点数和整数的规则)。

这应该更清楚为什么您发布的代码仍然产生有用的东西,即使代码刚刚被破坏。

【讨论】:

    【解决方案2】:

    %d对应的参数必须是int%f对应的参数必须是double。可变参数函数的参数经过一些标准转换(因此float 将自动转换为double),但它们不会自动转换为相应的printf 格式说明符的适当类型。

    【讨论】:

      【解决方案3】:

      并不难理解。 float 值在 float 寄存器中传递,而 int 值在常规参数堆栈中传递。因此,当引用这些值时,它们是从不同的区域获取的,并且它神奇地起作用,即使不应该(并且不会,在不同的盒子上)。

      【讨论】:

        【解决方案4】:

        例如,用于 amd64 的 gcc 4.7.2 会这样做,因为整数和浮点参数在不同的寄存器中传递。这有效地重新排序了参数。

        来自“System V 应用程序二进制接口。AMD64 架构处理器补充。草案版本 0.99.6”(浮点数具有 SSE 类):

        1. 如果类是 INTEGER,则使用序列 %rdi、%rsi、%rdx、%rcx、%r8 和 %r9 的下一个可用寄存器。
        2. 如果类是 SSE,则使用下一个可用向量寄存器,寄存器 从 %xmm0 到 %xmm7 的顺序。

        当然你不应该这样做,并在编译期间启用警告来捕获它。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-14
          • 1970-01-01
          • 2022-10-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-10-22
          • 1970-01-01
          相关资源
          最近更新 更多