【发布时间】:2009-04-07 21:28:05
【问题描述】:
下面是包含可变参数函数和调用可变参数函数的代码。我希望它会适当地输出每个数字序列。它在编译为 32 位可执行文件时会这样做,但在编译为 64 位可执行文件时不会。
#include <stdarg.h>
#include <stdio.h>
#ifdef _WIN32
#define SIZE_T_FMT "%Iu"
#else
#define SIZE_T_FMT "%zu"
#endif
static void dumpargs(size_t count, ...) {
size_t i;
va_list args;
printf("dumpargs: argument count: " SIZE_T_FMT "\n", count);
va_start(args, count);
for (i = 0; i < count; i++) {
size_t val = va_arg(args, size_t);
printf("Value=" SIZE_T_FMT "\n", val);
}
va_end(args);
}
int main(int argc, char** argv) {
(void)argc;
(void)argv;
dumpargs(1, 10);
dumpargs(2, 10, 20);
dumpargs(3, 10, 20, 30);
dumpargs(4, 10, 20, 30, 40);
dumpargs(5, 10, 20, 30, 40, 50);
return 0;
}
这是编译为 64 位时的输出:
dumpargs: argument count: 1
Value=10
dumpargs: argument count: 2
Value=10
Value=20
dumpargs: argument count: 3
Value=10
Value=20
Value=30
dumpargs: argument count: 4
Value=10
Value=20
Value=30
Value=14757395255531667496
dumpargs: argument count: 5
Value=10
Value=20
Value=30
Value=14757395255531667496
Value=14757395255531667506
编辑:
请注意,可变参数函数拉出size_t 的原因是因为它的实际用途是用于接受指针和长度列表的可变参数函数。自然地,长度参数应该是size_t。在某些情况下,调用者可能会传入一个众所周知的长度:
void myfunc(size_t pairs, ...) {
va_list args;
va_start(args, count);
for (i = 0; i < pairs; i++) {
const void* ptr = va_arg(args, const void*);
size_t len = va_arg(args, size_t);
process(ptr, len);
}
va_end(args);
}
void user(void) {
myfunc(2, ptr1, ptr1_len, ptr2, 4);
}
请注意,传递给myfunc 的4 可能会遇到上述问题。是的,调用者确实应该使用sizeof 或strlen 的结果,或者只是将数字4 放入size_t 某处。但关键是编译器没有捕捉到这一点(可变参数函数的常见危险)。
这里正确的做法是消除可变参数函数,并用提供类型安全的更好的机制取而代之。但是,我想记录这个问题,并收集更详细的信息来说明这个问题在这个平台上存在的确切原因以及它的表现。
【问题讨论】:
-
好问题。据我所知,只有 C++ 允许未命名的函数参数。我认为即使 C99 也不允许这样做。这一点,在编写纯 C 代码时,你不能这样做。 comeaucomputing.com/techtalk/#argwithnoname