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宏
*
作为后缀添加到函数指针类型,以创建指向该类型的指针,因为语法无效:
(双倍)(*)(双倍)
=>(双倍)(*)(双倍)*
但它可以添加到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分钟)。他们都很棒。