为什么下面代码中的第一个f()
调用最终会打印-2
而不是4294967294
?
#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdlib.h>
void f(int64_t i, ...)
{
va_list ap;
int64_t j;
va_start(ap, i);
j = va_arg(ap, int64_t);
printf("%jd %jd\n", (intmax_t) i, (intmax_t) j);
va_end(ap);
}
int main()
{
f(-1, -2); // Prints -1 4294967294 (bug!)
f(-1, (int64_t) -2); // Prints -1 -2 (fix!)
return 0;
}
我可以理解为什么第二个f()
调用修复程序有效。但我无法理解为什么第一个f()
调用会导致此问题。你能解释一下这种行为吗?
答案 0 :(得分:5)
在第一次调用中,参数将作为int
传递。除非使用64位表示int
,否则通过尝试从中提取int64_t
来调用未定义的行为。根据您的程序int
的输出判断,不会使用平台上的64位来显示。
来自第7.16.1.1/2节 C11标准(强调我的):
va_arg
宏扩展为具有指定类型和调用中下一个参数值的表达式。参数ap
应由va_start
或va_copy
宏初始化(无需干预va_end
的调用)。每次调用va_arg
宏都会修改ap
,以便依次返回连续参数的值。参数类型应该是指定的类型名称,以便只需通过将*固定为类型即可获得指向具有指定类型的对象的指针的类型。 如果没有实际的下一个参数,或者type与实际的下一个参数的类型不兼容(如同提升的那样) 对于默认参数促销),行为未定义,除以下情况外:- 一种类型是有符号整数类型,另一种类型是相应的无符号整数类型,并且该值可在两种类型中表示;
- 一种类型是指向void的指针,另一种是指向字符类型的指针。