![]() |
1
11
至少在x86-64上,var_args的传递相当复杂(由于在寄存器中传递参数)。其他架构可能不那么复杂,但很少是微不足道的。特别是,可能需要在获取每个参数时引用堆栈帧或帧指针。这些规则很可能会阻止编译器内联函数。 x86-64的代码包括将所有整数参数和8个sse寄存器推送到堆栈中。 这是用Clang编译的原始代码中的函数:
来自gcc:
在clang for x86中,它要简单得多:
没有什么能真正阻止上述代码被内联,所以看起来这只是编译器编写者的策略决定。当然,打个电话
(在过去一年的大部分时间里,我工作的一个重要部分是在OpenCL环境中实现printf,所以我知道的比大多数人都要多,甚至比大多数人查找到的格式说明符和printf的其他各种棘手部分都要多) 编辑:我们使用的OpenCL编译器将内联调用var_args函数,因此可以实现这样的功能。它不会对printf进行调用,因为它会使代码非常膨胀,但在默认情况下,我们的编译器始终内联所有内容,无论它是什么,但我们发现,代码中有2-3个printf副本会使其变得非常庞大(还有各种其他缺点,包括由于编译器后端的算法选择不当,最终代码生成需要更长的时间),因此我们必须添加代码以阻止编译器这样做。。。 |
![]() |
2
5
变量参数实现通常具有以下算法:从堆栈中获取格式字符串之后的第一个地址,在解析输入格式字符串时,将给定位置的值用作所需的数据类型。现在,用所需数据类型的大小递增堆栈解析指针,前进格式字符串并将新位置的值用作所需数据数据类型。。。等等
某些值会自动转换(即:升级)为“更大”类型(这或多或少取决于实现),例如
当然,您不需要格式字符串,但在这种情况下,您需要知道传入的参数的类型(例如:所有int,或所有double,或前3个int,然后3个double..)。 这就是简短的理论。 现在,就实践而言,正如上面n.m.的注释所示,gcc不内联具有可变参数处理的函数。在处理变量参数时,可能会进行非常复杂的操作,这会将代码的大小增加到非最佳大小,因此根本不值得内联这些函数。 编辑:
在使用VS2012进行了快速测试之后,我似乎无法说服编译器使用变量参数内联函数。
无论项目的“优化”选项卡中的标志组合如何,都会调用
http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx 说的是
|
![]() |
3
1
内联的目的是减少函数调用开销。
但对于瓦拉格来说,总体而言,几乎没有什么收获。
编译器应该如何内联它?这样做需要编译器以正确的顺序推送堆栈上的所有内容 无论如何 ,即使没有调用任何函数。唯一被优化的是一个call/ret指令对(可能还有推送/弹出ebp等等)。内存操作无法优化,参数也无法在寄存器中传递。因此,内联varargs不太可能获得任何显著的结果。 |
![]() |
4
1
我不认为内联varargs函数是可能的,除非是最普通的情况。 没有参数的varargs函数,或者不访问其任何参数,或者只访问变量之前的固定参数,可以通过将其重写为不使用varargs的等效函数来内联。这是一个微不足道的案例。
访问其可变参数的varargs函数通过执行
我看不出第二种情况的可行路径。 |
![]() |
Iliketoproveit · MATLAB函数中的变量参数对 7 年前 |
![]() |
jetstream · 变量参数和函数指针向量 7 年前 |
![]() |
WrathOfFlame · 解压缩函数调用的参数数组 7 年前 |
![]() |
flawr · 如何编写输出参数数目可变的匿名函数? 7 年前 |
![]() |
Tyler Jackson · 子类中变量函数特化的定义 7 年前 |
|
Brave Shine · Lisp&rest参数和递归调用 7 年前 |