我正在为Little Endian使用Visual Studio TC编译器 . 以下是这段代码:
void main()
{
float c = 1.0;
int a = 0x3F800000;
int *ptr = (int *)&c;
printf("\n0x%X\n", *ptr);
printf("\na = %f", a);
printf("\nc = %f", c);
return;
}
输出是:
0x3F800000
a = 0.000000
c = 1.000000
浮点值1.0为0x3F800000,并在内存中存储为00 00 80 3F,适用于Little Endian . 将相同的值分配给int a . printf如何打印0.000000一段时间1.000000 for float c?我已经看到它在printf中使用%f打印时将所有整数值打印为0.000000 .
另外,由于printf是可变参数函数,它如何知道寄存器中传递的值是int还是float?
7 回答
施放变量
在任何C实现中,都有关于如何将参数传递给函数的规则 . 这些规则可能会说某些类型的参数在某些寄存器中传递(例如,通用寄存器中的整数类型和单独的浮点寄存器中的浮点类型),大型参数(例如具有许多元素的结构)将在堆栈或指向结构副本的指针,依此类推 .
在被调用函数内部,该函数在规则指定的位置查找它所期望的参数 . 当你在一个参数中传递一个整数到
printf
但是在格式字符串中传递它%f
时,你在一个地方放一个整数,但是告诉printf
寻找一个浮点数(已被提升为一个双精度数) . 如果C实现的规则指定整数参数在double参数的同一位置传递,则printf
将找到整数的位,但它会将它们解释为double . 另一方面,如果C实现的规则为参数指定了不同的位置,那么整数的位不是printf
查找double的位置 . 所以printf
找到一些与你的整数无关的其他位 .此外,许多C实现具有32位
int
类型和64位double
类型 .%f
说明符用于打印double,而不是float,并且在调用函数之前传递的float值将转换为double . 所以,即使printf
找到整数的位,那里只有32位,但printf
使用64位 . 所以打印的double
由你传递的32位和32位其他位组成,这不是你的值打算打印 .这就是您使用 must 的格式说明符与您传递的参数匹配的原因 .
我遇到了类似的问题,最后我开发了一种方法来解决它,不确定这是否是你想要的 . 关键是:你应该传递一个浮点而不是一个整数 .
输出是这样的:
OS:Fedora21 64位GCC版本:gcc版本4.9.2 20141101(Red Hat 4.9.2-1)(GCC)
如
-Wall
所述:warning: format ‘%f’ expects type ‘double’, but argument 2 has type ‘int’
. 这是未定义的行为,也会更详细地解释here .If a conversion specification is invalid, the behavior is undefined. If any argument is not the correct type for the corresponding coversion specification, the behavior is undefined.
所以你在这里看到的是编译器构建器决定发生的事情,它可以是任何东西 .
我的通灵能力告诉我Adam Liss的评论是正确的答案:
float
参数被提升为double
,所以printf()
函数期望发生这种情况:它期望堆栈上的64位值,但是得到32位加上垃圾数据恰好为零 .如果提高显示精度,显示应类似于
a = 0.00000000001
.这也意味着这应该工作:
我已经用gcc编译了你的代码,生成的代码如下:
这可能会给你一个提示,浮动参数不是从常规堆栈中获取的,而是来自浮点堆栈...我希望会有一些随机而不是0 ...