在函数中访问未命名的参数,而不使用C中的stdarg.h

时间:2015-04-08 18:56:20

标签: c

我总是被告知,当你为参数留下一个空括号的函数定义时,该函数可以接受任意数量的参数或未知数量的参数,但我从未见过这个被使用过。

出于好奇,我想知道是否有办法访问传递给以这种方式定义的函数的参数。

就像打印参数的函数一样:

#include <stdio.h>

void emptyParent()
{
    // print arguments
}

int main(void)
{
    emptyParent(1, 2, 3);
    return 0;
}

3 个答案:

答案 0 :(得分:4)

在函数定义中:

void func() {
    /* ... */
}

空括号表示该函数没有参数。由于没有参数,无法访问参数。

在函数声明中,空括号表示该函数需要未指定但固定的数字和参数类型。在调用中,您必须传递定义指定的正确数量和类型的参数;没有这样做有未定义的行为。 (每个参数必须与相应参数的提升类型匹配。)编译器不会为您强制执行此操作。

在这两种情况下,这都是旧式语法,不应在新代码中使用。如果函数没有参数,请使用(void)声明并定义它。如果它具有固定数量的参数(一个或多个),则使用指定每个参数类型的原型声明和定义它,以便编译器可以在调用中强制执行正确的参数(在某些情况下,可以隐式转换适当类型的参数)。

如果需要可变数量的参数,则需要使用, ...语法和<stdarg.h>机制来访问函数内的参数。此机制需要最终命名参数才能启动;你不能声明或定义像

这样的函数
void this_is_invalid(...);

可能有一些方法可以在不使用该语言提供的功能的情况下模拟此机制,但没有其他便携式方法可以这样做。

答案 1 :(得分:1)

由于参数和局部变量都在堆栈上分配,并且假设在函数调用的堆栈上推送的已保存寄存器始终相同,您可以计算第一个局部变量和函数中第一个参数之间的偏移量(这里是computeOffset)并在函数中使用未定义的参数数量重新使用此偏移量:

#include <stdio.h>

int offset;

void computeOffset(int end)
{
    int start;

    offset = &end - &start;
}

void emptyParent()
{
    int *args;

    args = (int *)(&args + offset);
    printf("arg0 = %d\n", args[0]);
    printf("arg1 = %d\n", args[1]);
    printf("arg2 = %d\n", args[2]);
}

int main(void)
{
    computeOffset(0);
    emptyParent(1, 2, 3);
    return 0;
}

答案 2 :(得分:-1)

使用变量参数列表如下:

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

void emptyParent(int first, ...)
{
    // print arguments
    va_list ap;
    va_start(ap, first);
    // print first
    int max = va_arg(ap, int);
    int next = 0;
    while (next != -1) {
        next = va_arg(ap, int);
        // print next
    }
    va_end(ap);
    return 0; // something
}

int main(void)
{
    emptyParent(1, 2, 3, -1); // -1 marks the end of arguments
    return 0;
}