2011-04-13 74 views
1

代码:如何根据订购停止printf生成不同的值?

#include <stdio.h> 

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

输出:1.000000,1072693248,0,

代码:

#include <stdio.h> 

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

输出:3ff00000,0.000000,0

代码:

#include <stdio.h> 

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

输出:3ff00000,0,1.000000

这只是%u和%x消耗的字节数问题,以及如何让值变得一致?

回答

3

传递参数,它的类型不匹配格式字符串的相应组件会导致不确定的结果,因为你已经注意到了。特别是,"%x""%u"都期望类型的值(无符号)int。传递float(根据ABI,通常实际上会表示为doublelong double)在语义上不正确。

您的编译器应该警告您 - 如果没有,请确保您已启用所有警告(针对GCC的-Wall)。

如果你想1.0F为整数,只投:

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

如果你想获得二进制表示,尝试这样的事情:

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

完美。第二个正是我需要的。谢谢。 – deworde 2011-04-13 11:47:54

+0

为什么发生这种事情,请参阅http://stackoverflow.com/questions/2941095/convert-ieee-754-float-to-hex-with-c-printf – deworde 2011-04-13 14:07:49

+0

'float'作为'double'传递与ABI无关。这是标准的一部分。变量函数参数总是受到默认促销的影响,所以不可能将'float','char','short'或'_Bool'(或其任何有符号/无符号变体)作为可变参数传递。 – 2011-09-02 15:02:37

3

您通过第一个参数告诉printf什么参数:格式字符串。您传递给printf 的附加值必须与格式字符串匹配。如果他们不这样做,你会得到垃圾输出。在您的示例中,您正在传递一个浮点值,并且您正在告诉printf将其视为一个整数,格式说明符为%u。你因此得到垃圾输出。

man page for printf包含您需要为要打印的值创建正确格式字符串的所有详细信息。

0

这是参数列表与格式描述符不匹配的问题。如果你想打印1.0F为整数值,将其转换为第一个整数:

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

当我编译这个与海湾合作委员会我得到以下警告:

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’ 

这就是为什么你得到你的垃圾输出正在使用。用最严格的警告进行编译是一个好主意,这样您就可以及早发现这样的问题。

%u%x是期望无符号整数的格式说明符。对于所有示例,您应该使用%f浮点说明符。在给定浮点数的情况下,这总会给出一致的结果。

+1

为什么不将这些标志添加到您的答案以获得更完整的答案? – Johan 2011-04-13 10:33:04

2

你不能。

每个格式字段的格式都与format-specifier指定的类型完全相同。

在x86系统上,参数通常在堆栈上传递,而使用不正确的格式说明符会导致可变参数功能从堆栈中取错字节数。

对于您的情况,您可以使用3个浮点值调用printf,但将浮点值提升为double(请参见http://en.wikipedia.org/wiki/Type_conversion#Type_promotion_in_C-like_languages)。
所以在这种情况下(在x86系统上),堆栈上会有3个8字节的字节。

第一格式场将它期望在堆栈上的字节数:

  • %x将需要4个字节
  • %U还将4个字节
  • %F将采取8字节

所以格式字段的顺序将影响打印的实际数据。 (使用%f甚至有可能浮点值是无效的,这可能会导致崩溃)。

如果您想了解更多关于可变参数列表,看看答案在Passing of variable arguments in C

+0

这个回答颇具误导性。没有理由甚至期望参数在堆栈上传递;例如,在x86_64上,它们全都在寄存器中,浮点类型不会被解释为整数类型,反之亦然(相反,它们将不可见)。 – 2011-09-02 15:03:37

+0

你说得对。我会将这些信息添加到我的答案中。 – Patrick 2011-09-07 19:15:25