【发布时间】:2020-03-21 10:43:33
【问题描述】:
printf("%f", 1.0); //prints 1.0
但是
printf("%f", 1); // prints 0.0
转换是如何发生的?
【问题讨论】:
printf("%f", 1.0); //prints 1.0
但是
printf("%f", 1); // prints 0.0
转换是如何发生的?
【问题讨论】:
根据下面的@Eric Postpischil's 评论不同。
The first double argument (or float argument, which will be promoted to double if used with the ... part of a function) is put in %xmm0. The first “normal integer class” type of argument would go into %rdi. For printf, though, that pointer to the format string is the first argument of that class, so it does into %rdi. That means the first int argument passed goes into the second register for that class, which is %rsi. So, with printf("%f", 1);, printf looks for the floating-point value in %xmm0, but the caller puts an int 1 in %rsi
【讨论】:
int 的字节将被printf 解释为浮点数是不正确的。在一些常见的 C 实现中,尤其是使用 System V x86-64 ABI 的任何实现中,第一个 double 参数在 %xmm0 寄存器中传递,而 int 参数在传递格式字符串后传递给 printf %rsi。在处理%f 时,printf 会看到%xmm0 中的字节,而不是%rsi. 中的字节
double 参数(或float 参数,如果与函数的... 部分一起使用,将提升为double)放入%xmm0。第一个“普通整数类”类型的参数将进入%rdi。但是,对于printf,指向格式字符串的指针是该类的第一个参数,因此它确实存在于%rdi 中。这意味着传递的第一个int 参数进入该类的第二个寄存器,即%rsi. 因此,对于printf("%f", 1);,printf 在%xmm0 中查找浮点值,但调用者放置了一个int%rsi 中的 1 个。
并不是每个编译器都这样,有些实际上是打印 1.0。但是当指示 printf 打印一个双精度值时,您必须传递一个双精度值,而不是一个整数。你总是可以使用类型转换:
printf("%f", (double)1);
【讨论】:
printf("%f", 1);的情况下打印“1.0”的编译器吗?
printf("%f", 1); 导致未定义的行为,因为 double 是预期的,但您传递了 int。没有解释为什么它打印0.0,因为行为是未定义的。
【讨论】:
问题不在于 printf 函数本身,而在于编译器是否足够聪明。如果您的编译器不够聪明,那么它会将 printf 视为普通函数调用,并且不知道该函数的参数语法。所以它只是将一个字符串和一个整数放在堆栈上并调用该函数。 printf 函数接受第一个参数并开始将其解析为格式字符串。当它看到格式说明符%f 时,它会尝试将堆栈中的相应内存部分解释为浮点数。无法知道编译器之前将 int 值推到了那里。所以 printf 最好将内存解释为浮点数。结果取决于平台,即取决于 endiness 和 float/int 大小,还包括随机性,因为您很可能会在堆栈上遇到一些垃圾。在这种情况下 printf 所做的转换也可以这样看:
int i = 1; // Integer variable
int* pi = &i; // Pointer to i
float* pf = (float*)pi; // Reinterpret the pointer as floating point number address
float f = *pf; // Get the floating point from this address
printf("%f\n", f);
【讨论】:
int 都不会放入堆栈。指向字符串第一个字符的指针被放入寄存器,int 被放入另一个寄存器。如果传递了double 而不是int 1,它将被放入一个完全不同的寄存器中。结果是,当printf 为%f 查找double 时,它看不到int 1 的字节。它看到不同寄存器中的字节。
printf() 这里的东西除了接收基于你传入的格式的浮点数,在printf() 中将 int 打印为浮点数,你必须强制转换它
printf("%f", (float)1);
或
printf("%f",(double)1);
因为 C 会根据变量的类型和内存表示来处理传递给 printf() 的变量,并且您传递了错误的值,这将导致未定义的行为。
【讨论】: