Ниже приведен код, который включает в себя функцию с переменными числами и вызывает функцию с переменными числами. Я ожидаю, что он выведет каждую последовательность чисел соответственно. Это происходит при компиляции как 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
Edit:
Обратите внимание, что причина, по которой функция с переменным значением вытягивает значение 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);
}
Обратите внимание, что 4
, переданный в myfunc
, может столкнуться с проблемой, описанной выше. И да, действительно, вызывающий должен использовать sizeof
или результат strlen
или просто поместить число 4
в size_t
где-нибудь. Но дело в том, что компилятор не улавливает это (обычная опасность для переменных функций).
Правильно сделать здесь - исключить функцию переменной и заменить ее более совершенным механизмом, обеспечивающим безопасность типов. Однако я хотел бы задокументировать эту проблему и собрать более подробную информацию о том, почему именно эта проблема существует на этой платформе и проявляется так, как она есть.