【问题标题】:Is this the correct way to use va_arg with pointer to function?这是将 va_arg 与函数指针一起使用的正确方法吗?
【发布时间】:2016-05-09 10:43:23
【问题描述】:

在这样的函数中:

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));

我看到了this 文章,如果它不起作用,建议使用不同的方法:

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

答: 尝试对函数指针类型使用 typedef。 va_arg 宏通常玩的类型重写游戏被过于复杂的类型所阻碍,例如指向函数的类型。

就我而言,它适用于两个版本(GCC 5.2.1),这就是为什么我想知道一种方法比另一种更好吗?当我不首先键入指向函数的指针时是否存在一些潜在的错误?

【问题讨论】:

  • @KerrekSB 这可能是相关的,请参阅我的回答。
  • @2501:谢谢,很好的发现!

标签: c function-pointers variadic-functions


【解决方案1】:

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

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

7.16.1.1 va_arg 宏

  1. 参数type应该是一个类型 指定的名称使得指向具有指定类型的对象的指针的类型可以 只需在 type 后加上 * 即可获得。

因此,为了有兼容的代码,当使用函数指针时,你应该使用 typedef,因为 * 不能作为后缀添加到函数指针类型以创建指向该类型的指针,因为语法无效:

(double)(*)(double) => (double)(*)(double)*

但它可以添加到 typedef 中:

dfun => dfun*

【讨论】:

  • 听起来你真正想要的是typedef double fn(double);,没有指针,所以fn*就是double(*)(double)
  • @KerrekSB va_arg 不会附加*,只是 type 的命名必须这样,如果可以的话。有这个规则是因为宏限制了 C 语法。 typedef 可以是函数或函数指针。如果你 typedef 作为一个函数,那么程序员必须手动添加*
  • 哦,对了——当然,指针只是在内部使用。你得到的是你要求的实际类型。
【解决方案2】:

va_arg(args, type) 记录为(参见 ISO 9899:2011 §7.16.1.1 ¶2):

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

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

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

【讨论】:

  • 我接受上面的答案纯粹是因为它发布得更早(大约 3 分钟)。他们都很棒。
猜你喜欢
  • 1970-01-01
  • 2012-05-15
  • 1970-01-01
  • 2013-09-14
  • 1970-01-01
  • 1970-01-01
  • 2011-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多