c++传输二进制数据

文章目录

    • 一、前提
    • 二、二进制和指针相关概念
      • 1、二进制数据传输的本质
      • 2、指针相关概念
        • (1)float* 和char*类型的指针有什么区别吗
        • (2)c语言关于指针和长度的理解
      • 3、二进制传输步骤
    • 三、vector构造string对象
      • 1、vector和string的内存是否连续
        • (1)vector容器
        • (2)string对象
      • 2、vector和string的转换
        • (1)std::vector 转string
        • (2)string转float
      • 3、其他注意的点
        • (1) to_string的精度问题
        • (2)把一个vector追加到另一个vector的后面
    • 四、总结

一、前提

      需求是使用c++httplib库传输二进制的数据。传输前获取到的数据类型是std::vector类型。
      那么传输的数据要如何转换成二进制呢?二进制传输本质上传的是什么?为什么要进行指针的类型转换和长度转换?疑问有很多,不得不总结下了。

二、二进制和指针相关概念

1、二进制数据传输的本质

      首先明确,数据在计算机内存中的存储方式是二进制的,在进行数据传输的时候,从内存中读取出来的数据就是二进制的数据。
      因此,如果能保证数据存储上的连续性的话,我们只需要告诉httplib,传输数据的指针地址是什么,传输数据的长度是多少即可。httplib进行数据通信的时候,直接根据指针地址+len的方式就可以把数据都读出来进行发送。

2、指针相关概念

首先: c++是对c的一层封装,c里面关于内存数据的操作需要两个条件,一个是指针,一个是长度。
针对连续的内存,可以通过指针+长度的方式来操作内存。

(1)float* 和char*类型的指针有什么区别吗

      本质上都是指向数据的存储地址,区别在于指针类型,以及读出数据时候的格式转换。

float*类型的指针:指针运算的时候,因为float4个字节,需要转成1个字节,因此需要size*4.
char*类型的指针:指针运算的时候,因为char1个字节,因此直接获取size即可

(2)c语言关于指针和长度的理解

1)指针类型的理解

参考:02深入理解C指针之—指针类型和值

      指针指向的类型,只有知道指针指向的类型,才能明白指针在内存中的具体分布情况。特别是在指针的算术运算时,指针指向的类型决定要分配的内容的分布。

2)指针的值

      指针的值是指指针指向的某块内存区域的首地址,指针的内存区域可以用使用sizeof关键字获取指针的内存区域的大小,是以字节为单位,如果想获取指针上指针类型的大小,须要使用sizeof(指针名称)/sizeof(指针类型)

3)野指针和释放指针

野指针的出现:int *ptrnum; 只是声明指针,而不进行初始化出现野指针,野指针是内存泄漏的一种常见情况

参考:C++ 跟野指针说bye bye!

3、二进制传输步骤

1)获取vector容器的首元素地址指针,转换成char*格式,方便构造string对象。
(2)获取vector容器的size,因为float4个字节,需要转成1个字节,因此需要size*43)构造string对象是为了方便数据传输,socket操作的也是char类型的数据,且char类型占用字节比较少,因此这里转换成string类型,方便传输中的操作。通过vector的首个元素地址指针去迭代,从内存中读取数据,然后拷贝到string对象的连续内存块中
  (4) 实际网络传输的时候,会读取string对象,获取到char*指针,然后根据len长度来读取内存中的数据,这部分数据在内存中是以二进制的方式存储的,因此传输的是这部分二进制数据,也叫二进制传输。
注意:指针类型的改变只是为了保证数据的读取格式,以及明确根据len读取数据的地址步长,本质上数据是没有改变的,依然在内存中存储。

三、vector构造string对象

1、vector和string的内存是否连续

(1)vector容器

      其底层所采用的数据结构非常简单,就只是一段连续的线性内存空间。 vector 容器可以看做是一个动态数组,array容器则是静态数组。
data() : 返回指向容器中第一个元素的指针。

(2)string对象

      STL 的字符串类在申请内存的时候,总是切一块完整的内存。你可以理解为char* pString = new char[需要的尺寸]。 string类围绕这快内存进行了管理,如果新加入字符串,它会在原有的基础上使用realloc来扩大连续内存段。删除同理,所以String类的内存总是连续的。

c++的httplib库在构造参数的时候,参数类型是std::string,因此,需要转换类型,从vector转换成string类型。

2、vector和string的转换

(1)std::vector 转string

std::vector test_f;
//1、转换成char*
//2、利用string的构造函数构造
std::string ctc_log_prob_str((const char*)test_f.data(), test_f.size()*sizeof(float));

(2)string转float

auto *p_data = (float*) string.c_str(); //转换成float*
vector<float> data_float(p_data, p_data + file_len / sizeof(float)); //根据地址和len构造vector

把生成的string对象作为参数传给server端即可,server端通过req.get_file_value("xx").content.c_str()获取char*指针,然后处理数据。

3、其他注意的点

(1) to_string的精度问题

      to_string的精度默认是6,如果想要保存更高精度的话,需要手动设置。
关于to_string的精度问题:stackoverflow关于to_string的精度问题

以及setprecision设置精度,注意,这里设置的精度是全部字符的长度,
如果要针对小数点后的精度的话,需要加上:

setiosflags(ios::fixed)
std::cout << setiosflags(ios::fixed) << setprecision(3) << f;

参考:c++中setiosflags(ios::fixed)的用法

(2)把一个vector追加到另一个vector的后面

c++中的vector的插入操作有几个方法:

vector.insert(pos,elem);   //在pos位置插入一个elem元素的拷贝,返回新数据的位置。
vector.insert(pos,n,elem);   //在pos位置插入n个elem数据,无返回值。
 vector.insert(pos,beg,end);   //在pos位置插入[beg,end)区间的数据,无返回值 
vec1.insert(vec1.end(),vec2.begin(),vec2.end());  将vec2插入到vec1尾部

四、总结

      不得不承认,自己对比底层部分还是不够熟悉,特别是C语言的指针操作和对指针的理解上。有好有坏吧,知其然也要知其所以然,只要在前进的路上就好。共勉!

end

你可能感兴趣的:(c++,c++,算法,开发语言)