简体   繁体   English

该程序如何工作?

[英]How does this program work?

#include <stdio.h>

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

It displays a 0 !! 它显示0 How is that possible? 那怎么可能? What is the reasoning? 这是什么原因?


I have deliberately put a %d in the printf statement to study the behaviour of printf . 我特意在printf语句中添加了一个%d来研究printf的行为。

That's because %d expects an int but you've provided a float. 这是因为%d需要一个int但是您提供了一个float值。

Use %e / %f / %g to print the float. 使用%e / %f / %g打印浮点数。


On why 0 is printed: The floating point number is converted to double before sending to printf . 关于为什么打印0的原因:将浮点数转换为double然后发送给printf The number 1234.5 in double representation in little endian is 小尾数中双精度表示形式的数字1234.5为

00 00 00 00  00 4A 93 40

A %d consumes a 32-bit integer, so a zero is printed. %d使用32位整数,因此打印为零。 (As a test, you could printf("%d, %d\\n", 1234.5f); You could get on output 0, 1083394560 .) (作为测试,您可以printf("%d, %d\\n", 1234.5f);可以得到输出0, 1083394560 。)


As for why the float is converted to double , as the prototype of printf is int printf(const char*, ...) , from 6.5.2.2/7, 至于为什么将float转换为double ,因为printf的原型是int printf(const char*, ...)从6.5.2.2/7开始,

The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. 函数原型声明器中的省略号引起参数类型转换在最后声明的参数之后停止。 The default argument promotions are performed on trailing arguments. 默认参数提升是对尾随参数执行的。

and from 6.5.2.2/6, 从6.5.2.2/6开始,

If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double . 如果表示被调用函数的表达式的类型不包含原型,则对每个参数执行整数提升, 而将float类型的参数提升为double These are called the default argument promotions . 这些称为默认参数提升

(Thanks Alok for finding this out.) (感谢Alok找出这个问题。)

Technically speaking there is no the printf , each library implements its own, and therefore, your method of trying to study printf 's behavior by doing what you are doing is not going to be of much use. 从技术上讲存在printf ,每个库实现了自己,因此,你的努力学习方法printf做你正在做什么的行为是不会有太大的用处。 You could be trying to study the behavior of printf on your system, and if so, you should read the documentation, and look at the source code for printf if it is available for your library. 您可能正在尝试研究系统上printf的行为,如果是这样,则应阅读文档,并查看printf的源代码(如果库可用)。

For example, on my Macbook, I get the output 1606416304 with your program. 例如,在我的Macbook上,我的程序输出为1606416304

Having said that, when you pass a float to a variadic function, the float is passed as a double . 话虽如此,当您将float传递给可变参数函数时, float作为double传递。 So, your program is equivalent to having declared a as a double . 因此,您的程序等同于将a声明为double

To examine the bytes of a double , you can see this answer to a recent question here on SO. 要检查double的字节,您可以在SO上看到最近问题的答案

Let's do that: 让我们这样做:

#include <stdio.h>

int main(void)
{
    double a = 1234.5f;
    unsigned char *p = (unsigned char *)&a;
    size_t i;

    printf("size of double: %zu, int: %zu\n", sizeof(double), sizeof(int));
    for (i=0; i < sizeof a; ++i)
        printf("%02x ", p[i]);
    putchar('\n');
    return 0;
}

When I run the above program, I get: 当我运行上述程序时,我得到:

size of double: 8, int: 4
00 00 00 00 00 4a 93 40 

So, the first four bytes of the double turned out to be 0, which may be why you got 0 as the output of your printf call. 因此, double的前四个字节结果为0,这可能就是为什么printf调用的输出为0原因。

For more interesting results, we can change the program a bit: 为了获得更有趣的结果,我们可以对程序进行一些更改:

#include <stdio.h>

int main(void)
{
    double a = 1234.5f;
    int b = 42;

    printf("%d %d\n", a, b);
    return 0;
}

When I run the above program on my Macbook, I get: 当我在Macbook上运行上述程序时,我得到:

42 1606416384

With the same program on a Linux machine, I get: 在Linux机器上使用相同的程序,我得到:

0 1083394560

The %d specifier tells printf to expect an integer. %d说明符告诉printf期望一个整数。 So the first four (or two, depending on the platform) bytes of the float are intepreted as an integer. 因此,浮点数的前四个(或两个,取决于平台)字节被解释为整数。 If they happen to be zero, a zero is printed 如果它们恰好为零,则打印零

The binary representation of 1234.5 is something like 1234.5的二进制表示形式类似于

1.00110100101 * 2^10 (exponent is decimal ...)

With a C compiler which represents float actually as IEEE754 double values, the bytes would be (if I made no mistake) 使用C编译器实际上将float表示为IEEE754双float值,则字节将是(如果我没有记错的话)

01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000

On an Intel (x86) system with little endianess (ie the least significant byte coming first), this byte sequence gets reversed so that the first four bytes are zero. 在字节序很少的Intel(x86)系统上(即,最低有效字节排在最前面),该字节序列取反,因此前四个字节为零。 That is, what printf prints out ... 也就是说, printf打印出什么...

See This Wikipedia article for floating point representation according to IEEE754. 有关IEEE754的浮点表示,请参见此Wikipedia文章

It's because of the representation of a float in binary. 这是因为浮点数以二进制表示。 The conversion to an integer leaves it with 0. 转换为整数会使它保留为0。

Because you invoked undefined behaviour: you violated the contract of the printf() method by lying to it about its parameter types, so the compiler is free to do whatever it pleases. 因为您调用了未定义的行为:您对它的参数类型说谎,从而违反了printf()方法的约定,所以编译器可以自由地执行自己喜欢的事情。 It could make the program output "dksjalk is a ninnyhead!!!" 它可能使程序输出“ dksjalk是一个ninnyhead !!!” and technically it would still be right. 从技术上讲,这仍然是正确的。

The reason is that printf() is a pretty dumb function. 原因是printf()是一个非常愚蠢的函数。 It does not check types at all. 它根本不检查类型。 If you say the first argument is an int (and this is what you are saying with %d ), it believes you and it takes just the bytes needed for an int . 如果您说第一个参数是int (这就是您使用%d所说的话),则它会相信您,并且只占用int所需的字节。 In this case, asuming your machine uses four-byte int and eight-byte double (the float is converted to a double inside printf() ), the first four bytes of a will be just zeroes, and this gets printed. 在这种情况下,假设您的机器使用4字节的int和8字节的doublefloatprintf()内转换为double ),则a的前四个字节将仅为零,并且将其打印出来。

It won't convert automatically float to integer. 它不会自动将float转换为整数。 Because both has different format of storage. 因为两者具有不同的存储格式。 So if you want to convert, use (int) typecasting. 因此,如果要转换,请使用(int)类型转换。

#include <stdio.h>

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

Since you tagged it with C++ as well, this code does the conversion as you probably expect: 由于您也使用C ++对其进行了标记,因此此代码可以完成您可能期望的转换:

#include <iostream.h>

int main() {
    float a = 1234.5f;
    std::cout << a << " " << (int)a << "\n";
    return 0;
}

Output: 输出:

1234.5 1234

%d is decimal %d是十进制

%f is float %f浮动

see more of these here . 在这里看到更多这些。

You are getting 0 because floats and integers are represented differently. 由于浮点数和整数表示方式不同,因此得到0。

您只需要使用具有相关数据类型(int,float,string等)的适当格式说明符(%d,%f,%s等)。

It's not an integer. 不是整数。 Try using %f . 尝试使用%f

您要%f而不是%d

嘿,它必须打印一些东西,所以它打印了0。请记住,在C 0中还有其他所有内容!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM