这是使用带指针功能的va_arg的正确方法吗?

时间:2016-05-09 10:43:23

标签: 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  \t", tmp(x));
    }

    va_end(args);
}

如果我拉这样的论点是错的:

    double(*tmp)(double) = va_arg(args, double(*)(double));

我发现了this文章,如果它不起作用,会提出不同的方法:

  

问:我无法获取va_arg来引入类型指针到函数的参数。

     

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

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

2 个答案:

答案 0 :(得分:2)

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

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

  

7.16.1.1 va_arg宏

     
      
  1. 参数 type 应为类型   指定的名称,使得指向具有指定类型的对象的指针的类型可以   只需将* *后缀为类型即可获得。
  2.   

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

(double)(*)(double) =&gt; (double)(*)(double)*

但它可以添加到typedef:

dfun =&gt; dfun*

答案 1 :(得分: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 与实际的下一个参数的类型不兼容(根据默认参数提升而提升),则行为是未定义的,除了以下情况:

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

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