需求是使用c++
的httplib
库传输二进制的数据。传输前获取到的数据类型是std::vector
类型。
那么传输的数据要如何转换成二进制呢?二进制传输本质上传的是什么?为什么要进行指针的类型转换和长度转换?疑问有很多,不得不总结下了。
首先明确,数据在计算机内存中的存储方式是二进制的,在进行数据传输的时候,从内存中读取出来的数据就是二进制的数据。
因此,如果能保证数据存储上的连续性的话,我们只需要告诉httplib
,传输数据的指针地址是什么,传输数据的长度是多少即可。httplib
进行数据通信的时候,直接根据指针地址+len
的方式就可以把数据都读出来进行发送。
首先: c++
是对c
的一层封装,c
里面关于内存数据的操作需要两个条件,一个是指针,一个是长度。
针对连续的内存,可以通过指针+长度的方式来操作内存。
本质上都是指向数据的存储地址,区别在于指针类型,以及读出数据时候的格式转换。
float*类型的指针:指针运算的时候,因为float是4个字节,需要转成1个字节,因此需要size*4.
char*类型的指针:指针运算的时候,因为char是1个字节,因此直接获取size即可
1)指针类型的理解
参考:02深入理解C指针之—指针类型和值
指针指向的类型,只有知道指针指向的类型,才能明白指针在内存中的具体分布情况。特别是在指针的算术运算时,指针指向的类型决定要分配的内容的分布。
2)指针的值
指针的值是指指针指向的某块内存区域的首地址,指针的内存区域可以用使用sizeof
关键字获取指针的内存区域的大小,是以字节为单位,如果想获取指针上指针类型的大小,须要使用sizeof(指针名称)/sizeof(指针类型)
3)野指针和释放指针
野指针的出现:int *ptrnum; 只是声明指针,而不进行初始化出现野指针,野指针是内存泄漏的一种常见情况
参考:C++ 跟野指针说bye bye!
(1)获取vector容器的首元素地址指针,转换成char*格式,方便构造string对象。
(2)获取vector容器的size,因为float是4个字节,需要转成1个字节,因此需要size*4
(3)构造string对象是为了方便数据传输,socket操作的也是char类型的数据,且char类型占用字节比较少,因此这里转换成string类型,方便传输中的操作。通过vector的首个元素地址指针去迭代,从内存中读取数据,然后拷贝到string对象的连续内存块中
(4) 实际网络传输的时候,会读取string对象,获取到char*指针,然后根据len长度来读取内存中的数据,这部分数据在内存中是以二进制的方式存储的,因此传输的是这部分二进制数据,也叫二进制传输。
注意:指针类型的改变只是为了保证数据的读取格式,以及明确根据len读取数据的地址步长,本质上数据是没有改变的,依然在内存中存储。
其底层所采用的数据结构非常简单,就只是一段连续的线性内存空间。 vector
容器可以看做是一个动态数组,array
容器则是静态数组。
data
() : 返回指向容器中第一个元素的指针。
STL
的字符串类在申请内存的时候,总是切一块完整的内存。你可以理解为char* pString = new char[需要的尺寸]。
string
类围绕这快内存进行了管理,如果新加入字符串,它会在原有的基础上使用realloc
来扩大连续内存段。删除同理,所以String
类的内存总是连续的。
c++的httplib库在构造参数的时候,参数类型是std::string,因此,需要转换类型,从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));
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*
指针,然后处理数据。
to_string
的精度默认是6
,如果想要保存更高精度的话,需要手动设置。
关于to_string的精度问题:stackoverflow关于to_string的精度问题
以及setprecision
设置精度,注意,这里设置的精度是全部字符的长度,
如果要针对小数点后的精度的话,需要加上:
setiosflags(ios::fixed)
std::cout << setiosflags(ios::fixed) << setprecision(3) << f;
参考:c++中setiosflags(ios::fixed)的用法
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