Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
c变量函数_C_Function_Macros_Ellipsis_Variadic - Fatal编程技术网

c变量函数

c变量函数,c,function,macros,ellipsis,variadic,C,Function,Macros,Ellipsis,Variadic,我试图找出va_start(),va_arg()宏背后的原因。下面的代码运行良好 #include <iostream> #include <cstdarg> void f(double a, double b, ...) { va_list arg; va_start(arg, b); double d; while((d = va_arg(arg, double)) != 0) { std::cout <&

我试图找出va_start(),va_arg()宏背后的原因。下面的代码运行良好

#include <iostream>
#include <cstdarg>

void f(double a, double b, ...)
{
   va_list arg;
   va_start(arg, b);
   double d;
   while((d = va_arg(arg, double)) != 0)
      {
         std::cout << d << '\n';
      }
}

int main(int argc, char *argv[])
{
   f(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 0.0);
   return 0;
}
输出变为wierd,例如1 -0.0409377 -0.0409377 4.88084e-270 4.85706e-270 1. 2. 3. 4. 5. 6. 7. 8. 9
我认为可变参数放在最后一个声明的参数旁边,但显然有更复杂的情况。如果有人揭发我错在哪里或者那里到底发生了什么,我会非常高兴。

va_start、
va_arg
和不要忘记
va_end
是编译器特有的。你不能只是从别的地方把它们带到别的地方,期望它们发挥作用。如果你是一名编译工程师,你最好按照手册的内容使用它们,并且只尝试了解它们的内部工作原理

附言:哦,他们的定义通常是非常神秘的,使用微妙的技巧来让它工作


p.S2:在回答您的问题时,
\u builtin\u va\u arg
是在哪里定义的:编译器知道它,即所谓的builtin。您可以在编译器的源代码中找到它;)

您的手写宏将在一台机器上工作,该机器始终传递堆栈上的所有参数,并将较小的类型填充到sizeof(int)。然而,许多机器(现在大多数?)不在堆栈上传递参数,而是在寄存器中传递参数,只有当寄存器中的参数太多时才使用堆栈

因此,为了处理va_参数,编译器需要知道ABI以及在什么情况下将哪些参数放置在哪里。通常要做的是让一个va_列表包含多个数组(足以容纳可能包含arg的所有寄存器)和多个指针(通常,每种类型的寄存器一个,堆栈一个。va_start将所有参数寄存器转储到数组中并初始化指针,然后va_arg计算出将传入给定参数类型的哪种类型的寄存器,并从适当的位置提取值。对于一个假设的处理器,8个regs表示整数/指针args和8个regs用于float/double args,您可能有如下内容:

typedef struct {
    intptr_t iregs[8], *iptr;
    double   fregs[8], *fptr;
    char     *spptr;
} va_list;

inline void _builtin_va_start(va_list &ap, arg) {
    // dump the registers might be used to pass args into ap->iregs and ap-fregs,
    // setup iptr and fptr to point into iregs and fregs after the arguments that
    // correspond to 'arg' and those before it.  spptr points into the stack space
    // used for arguments after regs run out
}
inline _builtin_va_arg(va_list &ap, type) {
    if (type is integer or pointer) {
        if (ap->iptr == ap->iregs+8) {
            rv = *(type *)ap->spptr;
            ap->spptr += sizeof(type);
        } else {
            rv = *ap->iptr++;
        }
    } else if (type is float or double) {
        if (ap->fptr == ap->fregs+8) {
            rv = *(type *)ap->spptr;
            ap->spptr += sizeof(type);
        } else {
            rv = *ap->fptr++;
        }
    } else {
        // some other type (struct?) deal with it
    }
}

请注意,这两个
\u builtin\u va
函数都不能用C编写;它们需要内置到编译器中

为了清楚起见,您可能在编译器的源代码中找不到名为
\u builtin\u va\u arg
的函数。您将找到的代码可以识别实现定义的关键字并执行相应的操作与之相关的东西。它以与
+
sizeof
运算符基本相同的方式内置到编译器中。是的,我确实找不到它。感谢您的提示,让我以这种方式查看它。我以前没有提到过它,但手写宏可以与int类型一起工作,即所有参数都按照预期的方式放置,相对于上次定义的参数参数。在双类型的情况下,参数也在堆栈中,但以奇怪的方式,即我可以得到正确的结果,在指向最后一个参数的指针上加上最初的六个。这是某种填充吗?此外,我发现定义的参数有两个。你可以看到它将开始指针放在第一个参数上。你会得到它们,然后是四个数字一个接一个地重复所有参数。我知道知道知道它离实用性很远,但仍然很好奇。谢谢。
typedef struct {
    intptr_t iregs[8], *iptr;
    double   fregs[8], *fptr;
    char     *spptr;
} va_list;

inline void _builtin_va_start(va_list &ap, arg) {
    // dump the registers might be used to pass args into ap->iregs and ap-fregs,
    // setup iptr and fptr to point into iregs and fregs after the arguments that
    // correspond to 'arg' and those before it.  spptr points into the stack space
    // used for arguments after regs run out
}
inline _builtin_va_arg(va_list &ap, type) {
    if (type is integer or pointer) {
        if (ap->iptr == ap->iregs+8) {
            rv = *(type *)ap->spptr;
            ap->spptr += sizeof(type);
        } else {
            rv = *ap->iptr++;
        }
    } else if (type is float or double) {
        if (ap->fptr == ap->fregs+8) {
            rv = *(type *)ap->spptr;
            ap->spptr += sizeof(type);
        } else {
            rv = *ap->fptr++;
        }
    } else {
        // some other type (struct?) deal with it
    }
}