现在假设我必须使用字符串传递struct foo。该结构包含3个部分: 一个int,一个float和一个字符串:
struct foo {
int a;
float b;
string c;
}
我决定做的是编写一个简单的包装器来编码和解码这个struct foo:
string& encode_foo(const foo &input) {
// what do I do here?
// declare a string and fill in 4 bytes for a, 4 bytes for b and then c?
string ret;
ret.append((char*)(&input.a), 4); // This is really ugly, isn't it??
ret.append((char*)(&input.b), 4); // this is also very ugly??
}
foo decode_foo(const string &input) {
// get input.c_str() and cast to int and float?
}
我很好奇是否有一种优雅的方式来做到这一点?
答案 0 :(得分:2)
也许是这样的:
struct foo {
int a;
float b;
string c;
}
std::ostream& operator<<(std::ostream& os, const foo& f) {
return os << f.a << " " << f.b << " " << f.c;
}
std::istream& operator>>(std::istream& is, foo& f) {
return is >> f.a >> f.b >> f.c;
}
std::string encode(const foo& f) {
std::ostringstream oss;
oss << f;
return oss.str();
}
std::string decode(const std::string& s) {
std::istringstream iss( s );
foo f;
iss >> f;
return f;
}
int main() {
foo f;
std::string s=encode(f);
f=decode(s);
}
这样做的好处是:
std::cout << f
答案 1 :(得分:1)
选项可以是使用字符串流对结构字段进行编码结束解码。 这是一个简单的例子(但在更现实的代码中,你应该注意包含空格的字符串之类的东西等):
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
struct foo
{
int a;
float b;
string c;
};
string encode_foo(const foo& f)
{
ostringstream os;
os << f.a << ' ' << f.b << ' ' << f.c;
return os.str();
}
foo decode_foo(const string& s)
{
istringstream is(s);
foo f;
is >> f.a;
is >> f.b;
is >> f.c;
return f;
}
int main()
{
foo f1;
f1.a = 10;
f1.b = 3.14f;
f1.c = "hello";
string s = encode_foo(f1);
foo f2 = decode_foo(s);
cout << f2.a << '\n' << f2.b << '\n' << f2.c << endl;
}
输出:
10 3.14 hello
答案 2 :(得分:1)
使用ASN.1 binary encoding like DER or PER或Protocol Buffers。您可能还会找到this table of format comparisons useful。
基本上这些将数据标记为&#34;浮点,4字节&#34;或&#34;整数,8字节&#34;然后写二进制文件。这些格式是已知的和标准化的,因此实现可以在任何平台上读取它们。
您可以将它们存储在std::string
中,因为它实际上并不需要将数据空终止。但是,如果数据包含空值,则字符串的c_str()
函数将不起作用。
使用std::vector<unsigned char>
存储字节会更加困惑。
答案 3 :(得分:1)
警告: 以下代码使用当前平台的endian来处理数据。如果您将其发送到可能没有相同endian和其他相关架构参数的其他平台,请务必小心。
我将假设你明白你正在做的是将float的4个字节放入字符串的内存,而不是float的字符串表示。例如,对于值为2的整数,您将char值'\ 0','\ 0','\ 0','\ 2'放入字符串中。这与将'002'写成常规的人类可读字符串(第一个是3个空终止符加上十进制值为2的字符)不同。你也直接将float 的二进制表示注入到字符串中。
如果这是您想要的,那么您最好使用字符串以外的其他内容来存储值(maybe a std::vector<char>
/ std::vector<unsigned char>
)。例如:
std::vector<char>& encode_foo(const foo &input) {
// Note that these loops, as @DeadMG pointed out in comments, can be
// more easily accomplished with vector.insert( ... ), e.g.:
// vector.insert(vector.end(), adata, adata + sizeof(input.a));
std::vector<char> data;
char* adata = (char*)&input.a;
char* bdata = (char*)&input.b;
char* cdata = (char*)input.c.data();
for ( int i = 0; i < sizeof(input.a); ++i) {
data.push_back( *adata );
++adata;
}
for ( int j = 0; j < sizeof(input.b); ++j) {
data.push_back( *bdata );
++adata;
}
for ( int k = 0; k < input.c.length(); ++k) {
data.push_back( *cdata );
++cdata;
}
// Now, data contains the absolute minimum binary
// representation of the structure
// There are probably even simpler ways to do this,
// but the 3 loops are very explicit
// And demonstrate what you want.
// You could consider std::copy or memcpy instead if you need
// More flexibility.
return data;
}
foo decode_foo(const std::vector<char>& input) {
// Because you know the structure ahead of time, you can simply reverse the process
// Here, I'll use memcpy to show how that's used too
foo datafoo;
memcpy( datafoo.a, input.data(), sizeof(datafoo.a) );
// Offset by 4 (which is the typical size of an int
memcpy( datafoo.b, input.data() + sizeof(datafoo.a), sizeof(datafoo.b) );
// Now, we offset by 8, and each byte represents a character
// We can memcpy into a std::string's data and null-terminate it as needed
// By calling resize and telling it it's as big as the leftover data
// minus the size of the other structures
int offset = ( sizeof(datafoo.a) + sizeof(datafoo.b) );
int csize = input.size() - offset;
datafoo.c.resize( csize );
memcpy( datafoo.c.input.data(), input.data() + offset, csize );
// Usually, you don't use memcpy with strings,
// but this should do exactly as you want
return datafoo;
}
这不应该按照您的要求“浪费任何字节或空间”,但请记住,如果您想要二进制表示,则应该使用std::vector<char>
作为存储。此外,查看protobuff等内容以及其他此类数据打包和数据传输协议。您也可以使用上面的std :: string,但请记住,使用带有一些修改的std :: string会使该字符串在很多程序和例程中表现不佳,因为strings
是期望以null结尾,并且C ++中数字的二进制表示将为您解决问题。