我可以在“......”之前传递数组类型吗?我在哪里可以找到va_ *的宏代码

时间:2013-08-23 05:31:46

标签: c variadic-functions

  1. 我阅读了关于va_start的手册页并获取了这个:

      

    参数last是变量参数列表之前的最后一个参数的名称,也就是调用函数知道类型的最后一个参数。

         

    因为可以在va_start()宏中使用此参数的地址,   不应将其声明为寄存器变量,也不应声明为函数或      数组类型。

    我尝试了这段代码并且效果很好,但这让我很困惑。

    #include <stdio.h>
    #include <stdarg.h> 
    
    void va_func(int i[3],...);
    int main()
    {
          int m[3] = {0,1,2};
          va_func(m,4,5,5,6);
          return  0;
     }
    
     void va_func(int m[5],...)// I pass a array type here before the "..."
     {
          int i,j;
          va_list ap;
          va_start(ap,m);
          for(i = 0; i < 4 ;i++)
          {
              j = va_arg(ap,int);
              printf("argv[%d] is %d\n",i,j);
          }
          va_end(ap);
     }
    
  2. 然后我想阅读那些va_*宏的代码。但我从<stdarg.h>得不到任何结果 和<cstdarg>。任何黑客都可以告诉我如何以及在哪里可以学习va_*件事物?


  3. 这是我目前的问题:

    我想写一个Open(const char *path,int oflag, ...);函数。我希望它调用open并进行一些错误测试。

    int Open(const char * path,int oflag, ...)
    {
        int rt;
        rt = open(path,oflag,...)// I don't know how to do this now.
        if(rt == -1)
         err_deal_func();
        else
         return rt;
    }
    

3 个答案:

答案 0 :(得分:2)

C运行时无法知道传递了多少个参数。因此,不可能轻易转发论据。大多数接受转发参数的函数都会接受va_list对象(例如,参见vprintf)。

您需要了解传递的参数,以便能够判断您收到了多少参数。 printf能够通过读取格式字符串来实现,并且每次在字符串中看到占位符时,它都会读取下一个参数;但是如果你输入一个不正确的格式字符串或不正确的参数,你就会崩溃。

这也是open的作用:

  

oflag参数可能表示如果要创建文件   不存在(通过指定O_CREAT标志)。在这种情况下,打开需要一个   第三个论点mode_t mode;如上所述,使用模式模式创建文件   在chmod(2)中并由进程'umask value修改(参见umask(2))。

也就是说,如果oflag不包含O_CREAT,它不会尝试读取第三个参数。这也是你需要做的,正如你所看到的,它有点血腥。

如果您正在使用C ++(而不仅仅是普通的旧C),我建议您使用函数重载,它具有类型安全的附加好处(并且它是巨大的好处):

int Open(const char * path,int oflag)
{
    int rt = open(path,oflag);
    if(rt == -1)
     err_deal_func();
    else
     return rt;
}

int Open(const char * path,int oflag,mode_t mode)
{
    int rt = open(path,oflag,mode);
    if(rt == -1)
     err_deal_func();
    else
     return rt;
}

如果您确实需要在C(而不是C ++)中执行此操作,则需要使用oflag参数来确定是否需要读取其他参数。

int Open(const char* path, int oflag, ...)
{
    int rt;
    if ((oflag & O_CREAT) == O_CREAT)
    {
        // we have O_CREAT, this means that we were passed 3 arguments
        // declare argument list
        va_list ap;
        // create an argument list starting after the `oflag` argument
        va_start(ap, oflag);
        // read the next argument in `ap` as a `mode_t` variable
        mode_t mode = va_arg(ap, mode_t);
        // there are no more arguments to read, so clean up the list
        va_end(ap);

        // finally, call `open` passing that additional parameter
        rt = open(path, oflag, mode);
    }
    else
        rt = open(path, oflag);

    if (rt == -1)
        err_deal_func();
    else
        return rt;
}

答案 1 :(得分:1)

变量参数函数中...之前的参数是特殊的;标准称它为parmN,它用于提供有关变量参数部分的数量和可能类型的信息。

parmN将使用

va_start,因此无法省略:

void va_start(va_list ap, parmN);

如果是open

int open(const char *path, int oflag, ... );

oflag是特殊参数,open将检查它的值以确定它将作为变量参数部分接收的内容。

要开始一个简单的示例,您可以在C FAQ中查看this article

答案 2 :(得分:0)

在C / C ++中不可能有一个数组类型的参数:

  

参数声明为''数组类型''应调整为   ''指向类型的限定指针',......(C99标准,6.7.5.3第7段)

代码中的im都有int *类型。

在C / C ++中也不可能有函数类型的参数:

  

参数声明为''函数返回类型''应为   调整为''指向函数返回类型的指针'',...(C99标准,   6.7.5.3第8段)

因此,va_start文档中关于函数参数或数组类型的陈述似乎完全没有意义。