我有一个非常有趣的问题,我的朋友和同事都没有人帮助我。 那么,让我们来看看下一个c ++代码:
#include <stdio.h>
#include <stdarg.h>
typedef void* VirtualMethodTable;
void funcM(void* __this, ...);
__interface Ix
{
void __cdecl qq(long a, long b, double x, long c);
};
struct tagInterface
{
tagInterface()
{
VirtualMethodTable* VMT = new VirtualMethodTable[1];
VMT[0] = (void*)&funcM; //here's funcM assignment
this->VMT = VMT;
}
~tagInterface(){ delete[] VMT; }
VirtualMethodTable* VMT;
};
void func1(long a, long b, double x, long c)
{
//some_logic
}
void funcM(void* __this, ...)
{
va_list marker;
va_start(marker, __this);
marker -= sizeof(__this); // line 1
tagInterface* inst = va_arg(marker, tagInterface*); //line 2
//we can comment line 1 and line 2 and it still will work as earlier (doesn't work)
long l1 = va_arg(marker, long);
long l2 = va_arg(marker, long);
double d = va_arg(marker, double);//d = 4.343564450161e-311#DEN, not 3.3
long l4 = va_arg(marker, long);
func1(l1, l2, d, l4);
va_end(marker);
}
long main()
{
tagInterface x;
Ix* ins = (Ix*)((void*)&x);
long p1 = 1;
long p2 = 2;
double p3 = 3.3;
long p4 = 4;
ins->qq(p1, p2, p3, p4); //it will call funcM
}
它在Win32架构上运行良好(visual studio 2013,win7x64)
但是当我在x64上启动它时,函数funcM中的“d”变量有“4.343564450161e-311 #DEN”值
其他变量如“l1”,“l2”,“l4”,“inst”正常启动。
虽然,我试图使用'浮动',但它也不起作用!
我搜索了所有va_arg堆栈溢出问题,但没有找到答案!
那我哪里错了?
谢谢!
更新1。:
是的,因为“概念堆栈与物理堆栈不匹配”而无法正常工作
“d”变量通过xmm3寄存器,va_arg尝试使用xmm0。
希望smbd有时会发现它很有用!
更新2.解决问题!
对于64位程序,调用约定是不同的:值不总是通过堆栈传递:https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx。其中一些是通过寄存器传递的。因此,此处不能使用va_list(适用于堆栈并适用于变量参数函数)。
试试这个解决方法:
struct ClassIx
{
virtual void __cdecl qq(...);
};
ClassIx* ins = (ClassIx*)((void*)&x);
ins->qq(p1, p2, p3, p4); //it will call funcM
答案 0 :(得分:1)
va_arg
函数并调用它们。您没有拨打va_arg
功能,请拨打void __cdecl Ix::qq(long a, long b, double x, long c);
。
问题的一部分可能是&#34;我只是在堆栈上推送参数#34;。 堆栈不存在。这是一个概念性的C ++调用堆栈(所有已调用但尚未按时间顺序返回的函数列表及其参数)和物理x64堆栈(RBP / RSP寄存器)。
您的问题是概念堆栈与物理堆栈不匹配。并非所有功能参数都在物理堆栈上。 var_arg
机制必须动态地确定函数参数的位置,这可能意味着物理堆栈上的可变函数的参数是。