【发布时间】:2016-04-15 22:14:00
【问题描述】:
对于一个学校项目,我必须编写 C 函数 printf。事情进展得很顺利,但有一个问题我找不到很好的答案,所以我来了。
printf("PRINTF(d) \t: %d\n", -2147483648);
告诉我 (gcc -Werror -Wextra -Wall):
error: format specifies type 'int' but the argument has type 'long'
[-Werror,-Wformat]
printf("PRINTF(d) \t: %d\n", -2147483648);
~~ ^~~~~~~~~~~
%ld
但如果我使用 int 变量,一切都会顺利:
int i;
i = -2147483648;
printf("%d", i);
为什么?
编辑:
我明白了很多点,而且很有趣。无论如何,我猜printf 正在使用<stdarg.h> 库,所以va_arg(va_list ap, type) 也应该返回正确的类型。对于%d 和%i,显然返回的类型是int。有什么改变吗?
【问题讨论】:
-
对于我已经回答的其他问题,但随后我的评论已被删除:
va_arg()不知道您尝试获取的参数的类型。您需要知道这一点,如果您尝试获取与作为参数传递的类型不同的类型,那是未定义的行为。如果您执行printf("%d\n", -2147483648),这也适用,因为参数的类型为long,但printf尝试获取int。 -
不是重复的。如果您阅读了另一个问题的已接受答案,那是由于特定于问题上下文的未定义行为。这个问题与未定义的行为无关。这个问题是关于 C 的,另一个是关于 C++ 的。两种语言都有相似的推广规则,但可能存在细微差别。这个问题将帮助更多的未来访问者,如果更高的投票数有任何迹象,也许已经有了。
-
也不是第二个问题的重复。关键事实是他们以十六进制指定文字,这意味着它是无符号整数而不是有符号长。
-
@AdrianMcCarthy 他们以十六进制指定文字,这意味着它是无符号整数而不是有符号长整数。 这可以理解为“十六进制常量始终是无符号的”。旧的预标准 C 编译器通常使十六进制常量无符号,因此可能会造成混淆。每6.4.4.1 Integer constants, paragraph 5:“整数常量的类型是可以表示其值的相应列表的第一个。”在这种情况下,
0x80000000在这里是unsigned int,因为它适合unsigned int,但对于[signed] int来说太大了。 -
@AdrianMcCarthy 我重写了我的评论以表明我只是想澄清一下,并删除了我之前的评论