我想通过网络传输数据,但我不想使用任何外部库(标准C / C ++可以)。
例如:
unsigned int x = 123;
char y[3] = {'h', 'i', '\0'};
float z = 1.23f;
我想要这个
char xyz[11];
阵列。
注意: 要通过网络传输它,我需要无符号int(htonl函数)的网络字节顺序,然后我需要以某种方式将float序列化为IEEE 754格式(互联网上的许多功能),我知道。
如何让它们进入xyz-Array,端到端地排列好,所以我可以将它用作socket + send()函数的缓冲区?显然我有反向功能(ntohl和反向IEEE 754)来解决它们,但我也需要一种技术,最好是同样的......
这将是这样的:
xyz in binary: 00000000 0000000 00000000 01111011 | 01101000 | 01101001 | 00000000 | 00111111 10011101 01110000 10100100 - big endian repr. of u. int 123 - | - 'h' - | - 'i' - | - '\0' - | - IEEE 754 repr of float 1.23 -
如果没有外部库并且最少使用标准库函数,我怎样才能实现这一目标?这对我的课程来说并不像我这样学习。
答案 0 :(得分:18)
啊,你想要序列化原始数据类型!原则上,有两种方法:第一种方法是,您只需获取要序列化的数据的内部二进制表示形式,将其重新解释为字符,并在表示时使用它:
所以如果你有:
双d;
你取了那个地址,把那个指针重新解释为指向字符的指针,然后使用这些字符:
double *pd=&d;
char *pc = reinterpret_cast<char*>(pd);
for(size_t i=0; i<sizeof(double); i++)
{
char ch = *pc;
DoSomethingWith(ch);
pc++;
}
这适用于所有原始数据类型。这里的主要问题是,binray表示是依赖于实现的(主要取决于CPU)。 (当你尝试使用IEEE NANs时,你会遇到微妙的错误......)。
总而言之,这种方法根本不可移植,因为您无法控制数据的表示。
第二种方法是,使用更高级别的表示,您自己可以控制。如果性能不是问题,您可以使用std :: strstream和&gt;&gt;和&lt;&lt;运算符将原始C类型变量流式传输到std :: strings。这很慢但易于阅读和调试,并且非常便于携带。
答案 1 :(得分:8)
类似下面的代码会做到这一点。注意在不同系统上sizeof(unsigned int)不同的问题,那些会得到你。对于这样的事情,你最好使用定义明确的类型,比如int32_t。总之...
unsigned int x = 123;
char y[3] = {'h', 'i', '\0'};
float z = 1.23f;
// The buffer we will be writing bytes into
unsigned char outBuf[sizeof(x)+sizeof(y)+sizeof(z)];
// A pointer we will advance whenever we write data
unsigned char * p = outBuf;
// Serialize "x" into outBuf
unsigned int32_t neX = htonl(x);
memcpy(p, &neX, sizeof(neX));
p += sizeof(neX);
// Serialize "y" into outBuf
memcpy(p, y, sizeof(y));
p += sizeof(y);
// Serialize "z" into outBuf
int32_t neZ = htonl(*(reinterpret_cast<int32_t *>(&z)));
memcpy(p, &neZ, sizeof(neZ));
p += sizeof(neZ);
int resultCode = send(mySocket, outBuf, p-outBuf, 0);
[...]
...当然接收代码会做类似的事情,反之亦然。
答案 2 :(得分:1)
此discussion似乎与您的问题相关,但它使用了boost序列化API
答案 3 :(得分:0)
你的目标究竟是什么?你愿意使用的手段究竟是什么?
如果你只是想在一台特定的计算机上使用一个特定的编译器来完成工作,那么最快,最简单但也最脏的解决方案是使用联合。您定义一个将项目作为成员的结构,并将其与字符数组合并。你需要告诉编译器真正紧密地打包成员,这与#pragma pack(1)一致,你的问题就解决了。您只需将三个值存储在成员中,然后将其视为字符数组。
如果机器是小端,并且你需要big endian int / floats,你只需交换相关的字符。
但是如果你有其他目标,比如至少还有另外十几个解决方案,比如可移植性,非标准字节顺序,sizeof(int)!= 4,浮动内部不以IEEE格式存储,等等。