Jee*_*tel 0 c floating-point string-formatting
我有几个程序,其输出我无法理解:
#include <stdio.h>
int main(void)
{
int i=1;
float k=2;
printf("k is %f \n",k);
printf("i is %f \n",i);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出位于http://codepad.org/ZoYsP6dc
k is 2.000000
i is 2.000000
Run Code Online (Sandbox Code Playgroud)
再举一个例子
#include <stdio.h>
int main(void)
{
char i='a';
int a=5;
printf("i is %d \n",i); // here %d type cast char value in int
printf("a is %f \n",a); // hete %f dont typecast float value
printf("a is %f \n",(float)a); // if we write (float) with %f then it works
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出位于http://codepad.org/XkZVRg64
i is 97
a is 2.168831
a is 5.000000
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?为什么我显示输出?
首先,使用任何可变函数,例如printf()
,类型的所有整数值int
都被传递为int
(或unsigned int
在某些情况下在某些平台上),并且所有float
值都作为传递double
.(float)a
因此,你第二次投了double
.
其次,printf()
它本身会带你到你的话.如果你把垃圾送进去,就会把垃圾扔掉.更准确地说,如果你传递一个你告诉printf()
期望的整数double
,printf()
将尝试double
从参数列表中读取a .接下来发生的是未定义的行为.
一些编译器 - 尤其是GCC - 将报告文字字符串格式与相应参数列表之间的类型不匹配.如果您的常规编译器不进行该分析,请考虑使用一个编译器 - 至少对于初步编译来解决编译错误.
您可能正在64位x86架构上运行此应用程序.在此体系结构中,浮点参数在XMM寄存器中传递,而整数参数在通用寄存器中传递.请参阅System V AMD64 ABI约定.
因为%f
需要一个浮点值:
printf("i is %f \n",i);
Run Code Online (Sandbox Code Playgroud)
打印XMM0寄存器中的值,该值恰好是k
先前分配的值,而不是i
在RSI寄存器中传递.程序集看起来像这样:
movl $.LC1, %edi # "k is %f \n"
movsd .LC0(%rip), %xmm0 # float k = 2
call printf
movl $1, %esi # int i = 1
movl $.LC2, %edi # "i is %f \n"
call printf # prints xmm0 because of %f, not esi
Run Code Online (Sandbox Code Playgroud)
如果您重新排序这样的分配:
int i = 1;
printf("i is %f \n",i);
float k = 2;
printf("k is %f \n",k);
Run Code Online (Sandbox Code Playgroud)
它打印:
i is 0.000000
k is 2.000000
Run Code Online (Sandbox Code Playgroud)
因为XMM0寄存器恰好具有值0.
[更新]
它也可以在32位x86上重现.在这个平台printf()
基本上是铸造int*
到double*
,然后读取double
.让我们修改示例以便于查看:
int main() {
float k = 2;
int i = -1;
printf("k is %f \n",k);
printf("i is %f \n",i,i);
}
Run Code Online (Sandbox Code Playgroud)
64位输出:
k is 2.000000
i is 2.000000
Run Code Online (Sandbox Code Playgroud)
32位输出:
k is 2.000000
i is -nan
Run Code Online (Sandbox Code Playgroud)
也就是说,int
值为-1的2 s看起来像是double
0xffffffffffffffff,它是一个NaN
值.
归档时间: |
|
查看次数: |
885 次 |
最近记录: |