在C中将int打印为float

时间:2013-05-17 11:15:38

标签: c printf

我正在为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 个答案:

答案 0 :(得分:6)

我的精神力量告诉我Adam Liss的评论是正确的答案:float参数被提升为double,因此printf()函数期望这种情况发生:它期望64位堆栈上的值,但得到32位加上碰巧为零的垃圾数据。

如果提高显示精度,显示应该类似于a = 0.00000000001

这也意味着这应该有效:

void main()
{    
    double c = 1.0;
    long long a = 0x3FF0000000000000;
    long long *ptr = (long long *)&c;
    printf("\n0x%llX\n", *ptr);
    printf("\na = %f", a);
    printf("\nc = %f", c);
    return;    
}

答案 1 :(得分:5)

我已经在gcc中编译了你的代码,生成的代码如下:

movl    $0x3f800000, %eax
movl    %eax, -4(%ebp)
movl    $1065353216, -8(%ebp)
leal    -4(%ebp), %eax
movl    %eax, -12(%ebp)
movl    -12(%ebp), %eax
movl    (%eax), %eax
movl    %eax, 4(%esp)
movl    $LC1, (%esp)
call    _printf
movl    -8(%ebp), %eax
movl    %eax, 4(%esp)
movl    $LC2, (%esp)
call    _printf
flds    -4(%ebp)
fstpl   4(%esp)
movl    $LC3, (%esp)
call    _printf

这可能会给你一个提示,浮动参数不是从常规堆栈中获取的,而是来自浮点堆栈...我希望会有一些随机而不是0 ......

答案 2 :(得分:4)

正如-Wall所述:warning: format ‘%f’ expects type ‘double’, but argument 2 has type ‘int’。这是未定义的行为,也有更详细的解释here

如果转换规范无效,则行为未定义。如果任何参数不是相应的转换规范的正确类型,则行为未定义。

所以你在这里看到的是编译器构建器决定发生的事情,可以是任何事情。

答案 3 :(得分:2)

在任何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位,它不是你打算打印的值。

这就是您使用的格式说明符必须匹配您传递的参数的原因。

答案 4 :(得分:1)

我遇到了类似的问题,最后我开发了一种方法来解决它,不确定这是否是你想要的。重点是:你应该传递一个浮点而不是一个整数。

#include <stdio.h>
void printIntAsFloat();

int main(void){
    printIntAsFloat();
}

void printIntAsFloat(){
    float c = 1.0;
    int a = 0x3F800000;
    int *ptr = (int *)&c;
    float *fp = (float*)((void*)&a); /*this is the key point*/
    printf("\n0x%X\n", *ptr);
    printf("\na = %f", a);
    printf("\nc = %f", c);
    printf("\nfp = %f", *fp);
    return; 
} 

输出如下:

0x3F800000

a = 0.000000
c = 1.000000
fp = 1.000000
操作系统:Fedora21 64位 GCC版本:gcc版本4.9.2 20141101(Red Hat 4.9.2-1)(GCC)

答案 5 :(得分:-1)

施放变量

printf("\na = %f", (float)a);
printf("\nc = %f", (float)c);

答案 6 :(得分:-1)

int a= 0x3F800000;
printf("\na = %f", *(float*)&a);//1.0