为什么这个可变参数 C 函数不打印第一个参数?

Why does this variadic C function not print the first argument?

我正在尝试使用 stdarg.h 在 C 中创建一个可变参数函数,并且我遵循了本教程并完全按照他的方式编写了代码:https://www.youtube.com/watch?v=S-ak715zIIE。我在代码中包含了输出。我不明白为什么第一个参数没有打印出来,而且为什么最后打印了零?我很困惑。谢谢!

#include <stdio.h>
#include <stdarg.h>

void printNums(int num, ...) {
    va_list args;
    va_start(args, num);

    for (int i = 0; i < num; i++) {
        int value = va_arg(args, int);
        printf("%d: %d\n", i, value);
    }

    va_end(args);
}

int main() {
    printNums(5, 2, 3, 4);
    return 0;
}

/*
Output:
0: 2
1: 3
2: 4
3: 0
4: 0
*/

va_start 的第一个参数是 last 参数, 不是 可变参数。所以 num 持有 5,其余持有可变参数:

#include <stdio.h>
#include <stdarg.h>

void printNums(int num, ...) {
    va_list args;
    va_start(args, num);

    printf("%d: %d\n", 0, num);
    for (int i = 1; i <= num; i++) {
        int value = va_arg(args, int);
        printf("%d: %d\n", i, value);
    }

    va_end(args);
}

int main() {
    printNums(5, 2, 3, 4);
    return 0;
}
0: 5
1: 2
2: 3
3: 4
4: 0
5: 0

also, why are there zeros printed at the end? I am beyond confused. Thanks!

因为这一行:

    for (int i = 1; i <= num; i++) {

您将值 5 作为 num 传递给 printNums()。在 for 循环中,你表现得好像它描述了要读取的可变参数的数量,但它没有——你传递了 3 个可变参数,而不是 5 个。最后 2 次调用 va_start 因此会产生未定义的行为,因为你'已经阅读了有效可变参数的末尾。您在这里碰巧得到 0 只是偶然 - 它可能是其他随机值。

请注意,没有办法仅使用可变参数宏来了解如何传递许多参数。也没有办法断言他们的 type。如果您愿意,您可以假定它们的类型并在运行时指定它们的长度:

$ ./t3
0: 5
1: 2
2: 3
3: 4
#include <stdio.h>
#include <stdarg.h>

void printNums(int num, ...) {
    va_list args;
    va_start(args, num);

    for (int i = 0; i < num; i++) {
        int value = va_arg(args, int);
        printf("%d: %d\n", i, value);
    }

    va_end(args);
}

int main() {
    printNums(4, 5, 2, 3, 4);
    return 0;
}

可变参数函数在编写类似 printf 的函数时最有价值,其中需要未知类型和数量的参数(参见 the example from the man page)使用传递已知类型列表会更方便地完成传递数组并计数 int:

$ cat t.c
#include <stdio.h>

void printNums(int count, int* nums) {
    for (int i = 0; i < count; i++) {
        printf("%d: %d\n", i, nums[i]);
    }
}

int main() {
    int nums[] = {5,2,3,4};
    printNums(4, nums);
    return 0;
}

这并不能制作出关于可变参数的非常好的视频 :P