2
  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> and什么也没得到<cstdarg>。任何黑客都可以告诉我如何以及在哪里可以学习这些va_*东西吗?


这是我目前的问题:

我想写一个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;
}
4

3 回答 3

2

C 运行时无法知道传递了多少参数。因此,不可能那么容易地转发参数。大多数接受转发参数的函数都将接受一个va_list对象(参见vprintf示例)。

您需要了解您传递的参数才能知道您收到了多少。printf能够通过读取格式字符串来做到这一点,并且每次在字符串中看到占位符时,它都会读取下一个参数;但是如果你给它一个不正确的格式字符串或不正确的参数,你就会崩溃。

这也是这样open做的:

oflag如果文件不存在(通过指定O_CREAT标志) ,该参数可以指示将创建该文件。在这种情况下,open需要第三个参数mode_t mode;该文件是使用 chmod(2) 中所述的模式模式创建的,并由进程的 umask 值修改(请参阅 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;
}
于 2013-08-23T05:53:25.777 回答
1

The parameter before ... in a variable argument function is special; the standard calls it parmN and it's used to provide information about the number and possibly the type of the variable argument part.

parmN will be used by the macro va_start, so it can't be omitted:

void va_start(va_list ap, parmN);

In the case of open:

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

oflag is the special parameter, open will check the value of it to determine what it will receive as variable argument part.

For a simple example to start, you can check out this article in C FAQ.

于 2013-08-23T05:50:12.530 回答
0

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

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

您的代码中的iandm都有 type int *

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

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

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

于 2013-08-26T09:14:21.947 回答