【发布时间】:2012-03-11 01:52:12
【问题描述】:
使用 GCC 编译我的程序时,我收到以下警告:
format ‘%d’ expects type ‘int’, but argument 2 has type ‘long unsigned int
现在我只是通过玩弄我意识到 %lo 修复了警告。但是我真的不明白我在做什么。
是否有命名约定来获取类型的缩写形式?比如int是%d,为什么??
谢谢!
【问题讨论】:
使用 GCC 编译我的程序时,我收到以下警告:
format ‘%d’ expects type ‘int’, but argument 2 has type ‘long unsigned int
现在我只是通过玩弄我意识到 %lo 修复了警告。但是我真的不明白我在做什么。
是否有命名约定来获取类型的缩写形式?比如int是%d,为什么??
谢谢!
【问题讨论】:
不,有约定,你只需要look at the documentation。
格式说明符不是与类型的 1:1 映射,它们控制输出格式(因此得名)。单个输入值类型可以有多种输出格式。
例如,%d 是“十进制”,因为它将整数打印为十进制数。还有 %i ("integer") 做同样的事情。
对于unsigned int 值,您同时拥有%x(以十六进制打印)和%u(以八进制打印)。
【讨论】:
long unsigned int = unsigned long
您使用%lu 打印这些内容。
同样,%llu 代表unsigned long long。
%d - int
%u - unsigned
%ld - long
%lld - long long
%lu - unsigned long
%llu - unsigned long long
【讨论】:
int、long 等的定义是特定于目标的。如果 int 和 long 的大小匹配那么一个
printf("%d",var);
不会抱怨,但如果 long 是 64 位而 int 是 32 位为例,那么您将收到您描述的警告/错误。两种解决方案之一:
printf("%ld",var);
or
printf("%d",(int)var);
当然,对于后者,您必须确保编译器将 int 与 %d 大小相关联,如果您收到另一个警告,请进行相应调整。
编辑:
编译器试图通过担心 C 库的东西来帮助你,而这并不是编译器的真正业务。 printf() 使用可变数量的参数,希望您与格式字符串正确匹配。当 printf 在 32 位系统上看到 %d 时,它可能只会抓取下一个 32 位参数。但是,如果您将 64 位整数作为参数输入,它可能会抓取该整数的一半,并将另一半用作格式字符串中的下一项。例如
unsigned long ul;
float f;
f=3.4;
ul=0x3F9DF3B612345678;
...
printf("%X %f\n",ul,f);
根据您的系统、字节序等,如果上面的代码产生了这个输出,您一点也不应该感到惊讶:
12345678 1.234000
因为这是你告诉它的。您告诉它获取 ul 的低 32 位并将其打印为十六进制 (%X) 和 ul 的高 32 位并将其打印为 float (%f) 并将 f 放入函数调用中是浪费您没有提供任何格式化以使用浮点值。
现在,根据特定日期目标系统上的编译器,您可能会根据需要使上述代码工作,取一个系统/编译器,其中 unsigned long 被解释为 32 位,%X 被解释为 32 位,然后您会收到有关 64 位分配的警告,但 printf 更有意义。
由于这种痛苦,像 gcc 这样的编译器试图通过假设当您使用名为 printf() 的函数时您使用的是标准 C 函数并通过您的格式字符串解析寻找这些类型的常见错误。
【讨论】:
%lo = 以八进制数字打印的无符号长整数。是的,文档是一个很好的起点.. 但是有些东西有一个模式,比如 o 代表八进制,x 代表十六进制,l 代表任何长等等。习惯许多这样的格式说明符将帮助你在任何地方获得模式。
【讨论】:
但是我真的不明白我在做什么。
您所做的是告诉printf 函数如何按照格式字符串显示您提供的数据。您可能会发现%lo 并没有真正打印出您期望的结果——它打印的是正确的数据,而是以八进制(以 8 为基数)格式。
是否有命名约定来获取类型的缩写形式?比如int是%d,为什么??
“短格式”称为格式说明符。没有约定可以让您派生适当的 printf 格式说明符。你只需要look them up in an appropriate reference。
【讨论】: