带虚函数的结构体在32位程序和64位程序间交互注意事项

问题提出

     笔者编译了一个64位的应用程序,需要将一个结构体的内容发送给一个32位的应用程序解析,但是两边对结构体的sizeof求长度始终不一致,导致无法正常解析结构体数据。其中,发送端和接收端采用相同结构体定义和字节对齐,形式简化如下:

typedef struct _tagDEMO 
{
	int iVal1;
	virtual ~_tagDEMO(){}
}sDEMO;

发送端(64位应用程序)打包代码简化如下:

void SendBuf(sDEMO& ts)
{
    /// 申请空间
    int sz = sizeof(ts);
    char* pBuf = new char[sz];
    memset(pBuf,0,sz);

    /// 拷贝数据
    memcpy(pBuf,&ts,sizeof(ts));

    /// 发送数据
    ....

    /// 释放空间
    delete []pBuf;
}


接收端(64位应用程序)解包代码简化如下:

void rcvProc(char* pBuf,int len)
{
    sDEMO ts;
    memcpy(&ts, pBuf, sizeof(ts) );
}

 问题分析实验

        C++的类或者结构体中如果存在有虚函数,那么对其sizeof求长度的时候,这个长度是包含了虚函数表的指针地址长度的,而且这个虚函数表指针是放在结构体的最前面的,32位程序和64位程序对于指针长度的定义一个是4字节,一个是8字节,这也就导致了两边的结构体长度会不一致。

下面我们针对以上分析做如下实验:

1)结构体定义虚函数其结构体长度会增加

typedef struct _tagDEMO 
{
	int iVal1;
}sDEMO;

/// 
int main(int argc, _TCHAR* argv[])
{
	sDEMO ts;
	int sz = sizeof(ts);
	printf("sizeof(sDEMO) = %d\n",sz);
    ///
	return 0;
}

///
typedef struct _tagDEMO 
{
	int iVal1;
	virtual ~_tagDEMO(){}
}sDEMO;

/// 
int main(int argc, _TCHAR* argv[])
{
	sDEMO ts;

	int sz = sizeof(ts);
	printf("sizeof(sDEMO) = %d\n",sz);

	return 0;
}

 由此可见,增加一个虚函数其结构体长度增加了4(一个指针的长度,实验是在32位程序中运行的)。

2)结构体中不管定义多少个虚函数,都是增加一个指针长度(虚函数表指针)

///
typedef struct _tagDEMO 
{
	int iVal1;
	virtual ~_tagDEMO(){}
	virtual void vFun1(){}
	virtual void vFun2(){}
}sDEMO;

/// 
int main(int argc, _TCHAR* argv[])
{
	sDEMO ts;
	int sz = sizeof(ts);
    
	printf("sizeof(sDEMO) = %d\n",sz);

	return 0;
}

        多加了几个虚函数,结构体的长度仍然为8。

3)结构体数据中首先放置虚函数表指针

///
typedef struct _tagDEMO 
{
	int iVal1;
	virtual ~_tagDEMO(){}
	virtual void vFun1(){}
	virtual void vFun2(){}
}sDEMO;

/// 
int main(int argc, _TCHAR* argv[])
{
	sDEMO ts;
	ts.iVal1 = 10;
	int sz = sizeof(ts);
	printf("sizeof(sDEMO) = %d\n",sz);
	///
	char* pBuf = new char[sz];
	memset(pBuf,0,sz);
	memcpy(pBuf,&ts,sizeof(ts));
	printf("first 4 bytes = %d, second 4 bytes = %d\n",*( (int*)pBuf ),*( (int*)(pBuf + 4) ) );

	///
	return 0;
}

    前面4个字节并不是我们赋值的10,而是后面4个字节的值为10 

 问题解决办法

要在32位程序和64位程序之间传递结构体数据,一是在结构体中新增打解包的函数,利用打解包函数组织数据,例如:

///
typedef struct _tagDEMO 
{
	int iVal1;
	virtual ~_tagDEMO(){}
	virtual void vFun1(){}
	virtual void vFun2(){}
	void pack(char* &pBuf,int& len)
	{
		int offset = 0;
		/// 
		memcpy(pBuf + offset,&iVal1,sizeof(iVal1));
		offset += sizeof(iVal1);
		///
		len = offset;
	}
	void unpack(char* pBuf,int len)
	{
		int offset = 0;
		/// 
		memcpy(&iVal1,pBuf + offset,sizeof(iVal1));
		offset += sizeof(iVal1);
		///
	}
}sDEMO;

另外一种如果要保留直接拷贝结构体的方式,那么就需要将结构体中所有的虚函数去掉,如下所示:

///
typedef struct _tagDEMO 
{
	int iVal1;
    int iVal2;
    ///
    void Fun1();
}sDEMO;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

saint198

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值