开发者

How do I stop printf producing different values based on ordering?

Code:

#include <stdio.h>

int main()
{
    printf(
            " %f, %u, %x,\n", 1.0f, 1.0f, 1.0f);
    return 0;
}

Output: 1.000000, 1072693248, 0,

Code:

#include <stdio.h>

int main()
{
    printf(
            " %x, %f, %u,\n", 1.0f, 1.0f, 1.0f);
    return 0;
}

Output: 3ff00000, 0.000000, 0

Code:

#include <stdio.h>

int main()
{
    printf(
            " %x, %u, %f,\n", 1.0f, 1.0f, 1.0f);
    return 0;
}

Output: 3ff00000, 0, 1.000000

开发者_如何学运维

Is this just an issue with the number of bytes that %u and %x consume, and how do I get the values to become consistent?


Passing arguments whose type does not match the corresponding component of the format string will lead to undefined results, as you've noticed. In particular, "%x" and "%u" both expect values of type (unsigned) int. Passing a float (which will often actually be represented as a double or long double depending on the ABI) is semantically incorrect.

Your compiler should be warning you about this - if not, make sure you've got all warnings enabled (-Wall for GCC).

If you want 1.0f as an integer, just cast:

printf(" %x, %u, %f\n", (unsigned)1.0f, (unsigned)1.0f, 1.0f);

If you're trying to obtain the binary representations, try something like this:

float a = 1.0f;
printf(" %x, %u, %f\n", *((unsigned*)&a), *((unsigned*)&a), a);


You tell printf what arguments to expect via the first parameter: the format string. The additional values you pass to printf must match the format string. If they don't you get garbage output. In your examples, you are passing a floating point vale 1.0f and you're telling printf to treat it as an integer with %u format specifier. You thus get garbage output.

The man page for printf has all of the details you need to create the correct format string for the values you want to print.


You can't.

Every format-field expects exactly the same type as specified by the format-specifier.

On x86 systems, arguments are often passed on the stack, and using an incorrect format-specifier will cause the variable-argument functionality to take the wrong number of bytes from the stack.

In your case, you call printf with 3 floating point values, but floating point values are promoted to double (see http://en.wikipedia.org/wiki/Type_conversion#Type_promotion_in_C-like_languages).
So in this case (on x86 systems), there will be 3 times 8 bytes on the stack.

The first format-field will take the number of bytes it expects on the stack:

  • %x will take 4 bytes
  • %u will also take 4 bytes
  • %f will take 8 bytes

So the order of the format-fields will have an influence on the actual data that is printed. (with %f it is even possible that the floating-point value is an invalid one, which may cause a crash).

If you want to know more about variable argument lists, look at the answers in Passing of variable arguments in C


When I compile this with gcc I get the following warnings:

crazy.c: In function ‘main’:
crazy.c:4: warning: format ‘%u’ expects type ‘unsigned int’, but argument 3 has type ‘double’
crazy.c:4: warning: format ‘%x’ expects type ‘unsigned int’, but argument 4 has type ‘double’
crazy.c:5: warning: format ‘%x’ expects type ‘unsigned int’, but argument 2 has type ‘double’
crazy.c:5: warning: format ‘%u’ expects type ‘unsigned int’, but argument 4 has type ‘double’
crazy.c:6: warning: format ‘%x’ expects type ‘unsigned int’, but argument 2 has type ‘double’
crazy.c:6: warning: format ‘%u’ expects type ‘unsigned int’, but argument 3 has type ‘double’

This is why you get the garbage output that you are using. It's a good idea to compile with the strictest warnings possible so you can get early notice of problems like this.

%u and %x are format specifiers that expect unsigned integers. You should be using the %f floating point specifiers for all of the examples. This would always give consistent results given floating point numbers.


This is issue with argument list do not match format descriptors. If you want to print 1.0f as integer value, convert it to integer first:

printf("%x, %u, %f,\n", (int)1.0f, (int)1.0f, 1.0f);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜