有没有办法计算 va_list
的长度?我看到的所有示例都明确给出了变量参数的数量。
原文由 Anton Kazennikov 发布,翻译遵循 CC BY-SA 4.0 许可协议
有没有办法计算 va_list
的长度?我看到的所有示例都明确给出了变量参数的数量。
原文由 Anton Kazennikov 发布,翻译遵循 CC BY-SA 4.0 许可协议
嗯,如果你不害怕讨厌的 asm hack,那么你可以利用编译器的调用约定。但是,这会将您的代码限制为特定的平台/编译器/调用约定。
例如,在 BDS2006 C++ 32bit x86 Windows 应用程序(我将仅参考此平台)中,将参数放入堆栈然后调用,然后在函数返回后修复堆栈指针值(通过使用堆栈的大小)。这里的小例子:
double x;
x=min(10.0,20.0,30.0,40.0,50.0);
电话被翻译成这样:
Unit1.cpp.28: x=min(10.0,20.0,30.0,40.0,50.0);
00401B9C 6800004940 push $40490000
00401BA1 6A00 push $00
00401BA3 6800004440 push $40440000
00401BA8 6A00 push $00
00401BAA 6800003E40 push $403e0000
00401BAF 6A00 push $00
00401BB1 6800003440 push $40340000
00401BB6 6A00 push $00
00401BB8 6800002440 push $40240000
00401BBD 6A00 push $00
00401BBF E894FDFFFF call min(double,double,????)
00401BC4 83C428 add esp,$28
注意通话后的最后一条指令。 $28
是 4 个参数和一个返回值消耗的大小。因此,如果您可以在函数中读取该值,则可以准确确定参数的数量(如果它们的大小已知)。所以这里的工作示例:
double min(double x,double ...) // = min(x,y)
{
int n,dn=sizeof(double);
asm {
mov eax,esp // store original stack pointer
mov esp,ebp // get to the parrent scope stack pointer
pop ebx
pop ebx // this reads the return address of the call pointing to the first instruction after it which is what we want
mov esp,eax // restore stack pointer
sub eax,eax; // just eax=0
mov al,[ebx+2] // read lowest BYTE of eax with the $28 from the add esp,$28
mov n,eax // store result to local variable for usage
}
n-=dn; // remove return value from the count
double z; z=x;
va_list va;
va_start(va,x); n-=dn;
for (;n>=0;n-=dn)
{
x=va_arg(va,double);
if (z>x) z=x;
}
va_end(va);
return z;
}
注意每个编译器可以有不同的调用顺序,所以在使用前调试时首先检查汇编列表!!!
原文由 Spektre 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答1.6k 阅读✓ 已解决
无法计算
va_list
的长度,这就是为什么您需要printf
中的格式字符串之类的函数。可用于处理
va_list
的唯一功能宏是:va_start
开始使用va_list
va_arg
- 获取下一个参数va_end
- 停止使用va_list
va_copy
(C++11 和 C99 起)- 复制va_list
请注意,您需要在同一范围内调用
va_start
和va_end
这意味着您不能将其包装在一个实用程序类中,该实用程序类在其构造函数中调用va_start
和va_end
在它的析构函数中(我曾经被这个咬过)。例如,这个类毫无价值:
GCC 输出 以下错误