1. 前情提要

  1. 如题,最近项目程序里使用zmq通信,原意是要将一个vector<vector<Point>>类型的数据结构从Req发送到ReP端,然后对其进行操作。但是本人试过之后发现一旦将其打包好,发送过去,另一端无法访问到内层结构及数据,(相当于传了一个黑盒过去,而自己却需要内部的数据。。。)可能需要处理把整个结构完好无损的发过去才能访问到吧。无奈本人才疏学浅,不知道要怎么打包整个结构。有幸看到这里的大佬如果有想法还请不吝赐教!!!
  2. 再说回来,不会怎么办呢,来个曲线救国,我把整个结构给它压缩成了一维:
int *rawData = new int[num];

像这样,new了一个指针数组,把所有数据都由这个指针数组来指向。然后将指针数组发送过去,实现间接访问。

2. memcpy函数

函数原型
void *memcpy(void*dest, const void *src, size_t n);
函数源码
void* MyMemcpy(void* dest,const void* src,size_t num)
{
     assert(dest&&src);
     char* dest_t=(char*)dest;//目标字符串
     const char* src_t=(const char*)src;//源字符串
     while(num--)
     {
         *dest_t++= *src_t++;
     }
     return dest;
}
//(不能解决内存重叠的问题,正序拷贝,适用于任何类型)
功能

由src指向地址为起始地址的连续n个字节的数据复制到以destin指向地址为起始地址的空间内。

说明

1.source和destin所指内存区域不能重叠,函数返回指向destin的指针。
2.与strcpy相比,memcpy并不是遇到’\0’就结束,而是一定会拷贝完n个字节。
3.memcpy用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度;
4. 要注意,它是以字节为单位一个一个拷贝!!!(不幸跌入这个坑)
5. memcpy函数没有处理内存重叠问题,要注意。

3. 顺带记录一下邻居memmove函数

众所周知,这两个函数最大的不同就是一个需要程序员自己控制内存,不能重叠,否则会出错;另一个即memmove函数则解决了这个内存区域重叠的问题。

memmove函数原理

void* memmove(void* dest, const void* src, size_t n)
{
    char * d  = (char*) dest;
    const char * s = (const char*) src;
    assert(dest&&src);
    if (s>d)
    {
         // 无内存重叠,从低地址拷贝
         while (n--)
            *d++ = *s++;
    }
    else if (s<d)
    {
        // 有内存重叠,从高地址拷贝,将指针调到最后
        d = d+n-1;
        s = s+n-1;
  
        while (n--)
           *d-- = *s--;
    }
	
    return dest;
}

在此不做过多介绍,文末附上大佬链接,感兴趣的可以去研究。

4. 坑

我定义并初始化的这个指针数组,假设长度为nLength。我在zmq的发送端Req通过指针传参是这样复制的:

void CRequest::SendRequest(int* rawData, int nLength)
{
	 void *context = zmq_init(1);
	 void *z_socket = zmq_socket(context, ZMQ_REQ);

	 // 绑定ip端口
	 string strConInfo = m_strConInfo;
	 zmq_connect(z_socket, strConInfo.c_str());  //建立ip+端口连接
	 //发送部分
	 zmq_msg_t send_msg;
	 //方式1——错误
	 //int nRc = zmq_msg_init_size(&send_msg, nLength);//初始化指令信息
	 //memcpy((int *)zmq_msg_data(&send_msg), rawData, nLength);//拷贝
	 //方式1——改正
	 //int nRc = zmq_msg_init_size(&send_msg, nLength*4);//初始化指令信息
	 //memcpy((int *)zmq_msg_data(&send_msg), rawData, nLength*4);
	 //方式2
	 int nRc = zmq_msg_init_data(&send_msg, rawData, nLength, NULL, NULL);//错误
	//int nRc = zmq_msg_init_data(&send_msg, rawData, nLength*4, NULL, NULL);//改正
	 zmq_msg_send(&send_msg, z_socket, 0);  //发送请求
	 zmq_msg_close(&send_msg);
	 //接收部分,略
	 ...
	 zmq_close(z_socket);
	 zmq_term(context);
}

两种方式本质都是一样的,这里由于是基于字节拷贝的,一直没注意到,导致把长度作为size。发到另一端后,遍历指针数组时,后面部分数据输出直接一堆乱码。代码庞大,检查了好久快要躺尸时,最终定位到了这里,害。

5. 解决

解决办法就很明了了,将nLength*4,(int型是4字节),当然在接收端遍历时也要再除以4恢复指针数组的长度。

————
有时候,一个问题没解决前觉得怎么这么难,可真当解决了吧,又觉得这么简单怎么就没想到,可真让人头大。

链接:
memcpy和memmove函数的区别和实现

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐