C 这是将va_arg与指向函数的指针一起使用的正确方法吗?

C 这是将va_arg与指向函数的指针一起使用的正确方法吗?,c,function-pointers,variadic-functions,C,Function Pointers,Variadic Functions,在这样的函数中: typedef double(*dfun)(double); void tab(double x, int n, ...) { va_list args; va_start(args, n); printf("%5.2lf \t", x); for (int i=0; i<n; i++) { dfun tmp = va_arg(args, dfun); printf(" %5.2lf

在这样的函数中:

typedef double(*dfun)(double);

void tab(double x, int n, ...)
{
    va_list args;

    va_start(args, n);

    printf("%5.2lf  \t", x);

    for (int i=0; i<n; i++)
    {
        dfun tmp = va_arg(args, dfun);

        printf("  %5.2lf  \t", tmp(x));
    }

    va_end(args);
}
    double(*tmp)(double) = va_arg(args, double(*)(double));
我看到一篇文章,其中提出了一种不同的方法,如果它不起作用:

Q:我无法让va_arg引入指向函数指针类型的参数

A:尝试对函数指针类型使用typedef。 va_arg宏通常玩的类型重写游戏受到过于复杂的类型(如指向函数的指针)的阻碍


在我的例子中,它可以在两个版本(GCC 5.2.1)中工作,这就是为什么我想知道一种方法比另一种更好吗?如果不首先键入指向函数的指针,是否存在潜在错误?

在某些情况下,使用不带typedef的指针确实会导致问题

标准说明,在
va_arg
中使用的
type
必须以某种方式写入,其中添加后缀
*
将创建指向
type
的指针:

7.16.1.1 va_arg宏

  • 参数类型应为a类型 指定的名称,以便指向具有指定类型的对象的指针的类型可以 只需将a*后固定到类型即可获得
  • 因此,要获得兼容的代码,在使用函数指针时,应使用typedef,因为不能将
    *
    作为后缀添加到函数指针类型,以创建指向该类型的指针,因为语法无效:

    (双倍)(*)(双倍)
    =>
    (双倍)(*)(双倍)*

    但它可以添加到typedef中:

    dfun
    =>
    dfun*
    va_arg(args,type)
    记录如下(参见ISO 9899:2011§7.16.1.1¨2):

    va_arg
    宏扩展为具有指定类型和调用中下一个参数值的表达式。参数
    ap
    应已由
    va_start
    va_copy
    宏初始化(无需对同一ap调用
    va_end
    宏)。每次调用va_arg宏都会修改ap,以便依次返回连续参数的值。参数类型应为指定的类型名称,以便指向具有指定类型的对象的指针的类型可以 只需将
    *
    后固定到类型即可获得。如果没有实际的下一个参数,或者如果类型与实际的下一个参数的类型不兼容(根据默认参数升级进行升级),则行为未定义,但以下情况除外:

    • 一种类型是有符号整数类型,另一种类型是相应的无符号整数类型,值在两种类型中都可以表示
    • 一种类型是指向void的指针,另一种类型是指向字符类型的指针

    因此,
    va_arg(args,double(*)(double))
    不是对
    va_args
    的有效调用,因为
    double(*)(double)*
    是一个语法错误,而不是指向
    double(*)(double)
    的指针类型,后者将是
    double(**)(double)
    。因此,类型定义需要符合标准。GNU C编译器是仁慈的,因为它不需要这种语法限制,但您的代码可能无法用其他编译器编译。

    @KerrekSB可能相关,请参阅我的答案。@2501:谢谢,很好的发现!听起来你真正想要的是
    typedef-double-fn(double)
    ,没有指针,因此
    fn*
    double(*)(double)
    @KerrekSB。va_arg不会附加
    *
    ,只是类型的命名必须是这样的,如果可以的话。之所以存在此规则,是因为宏限制了C语法。Typedef可以是函数,也可以是指向函数的指针。如果您将def作为函数键入,那么程序员必须手动添加
    *
    。哦,对了-当然,指针只是在内部使用的。你得到的是你要求的实际类型。我接受了上面的答案,纯粹是因为它被张贴得更快(大约3分钟)。他们都很棒。