【发布时间】:2014-12-08 15:41:12
【问题描述】:
假设我正在尝试从文件中读取数据。数据存储为二进制数据,可以使用编译器打包扩展轻松读取(为清楚起见,使用 C99 表示法):
#pragma pack(push, 1) /* visual studio */
struct S
{
int16_t v1;
uint32_t v2; /* gcc would use: __attribute__((packed)) */
int16_t v3;
};
#pragma pack(pop)
void read( std::istream & is )
{
S s;
assert( sizeof(s) == 8 ); // packed !
is.read( (char*)&s, sizeof(s) );
std::cout << s.v1 << " " << s.v2 << " " << s.v3 << std::endl;
}
编写相同的代码但考虑到可移植性会变得更加混乱:
struct S2
{
unsigned char buf1[2];
unsigned char buf2[4];
unsigned char buf3[2];
};
static inline uint16_t makenum(const unsigned char (&x)[2])
{
return x[0] | (x[1] << 8);
}
static inline uint32_t makenum(const unsigned char (&x)[4])
{
return
((uint32_t)x[0] << 0)
| ((uint32_t)x[1] << 8)
| ((uint32_t)x[2] << 16)
| ((uint32_t)x[3] << 24);
}
void read( std::istream & is )
{
S2 s2;
assert( sizeof(s2) == 8 ); // garanteed !
is.read( (char*)&s2, sizeof(s2) );
std::cout << makenum(s2.buf1) << " " << makenum(s2.buf2) << " " << makenum(s.buf3) << std::endl;
}
还有什么(更聪明的)可以做的吗?我猜移位和按位包含 OR 应该不会对执行产生太大影响,但是我找不到使用 union 的通用解决方案来避免计算。例如:伪解决方案(不工作):
struct S3
{
union { char buf1[2]; int16_t v1; } uv1;
union { char buf2[4]; uint32_t v2; } uv2;
union { char buf3[2]; int16_t v3; } uv3;
};
【问题讨论】:
-
我怀疑是否有使用简单结构来解决您的问题(尤其是跨平台)的真正可移植解决方案。你应该看看
boost::serialization或gooble protocol buffers 来实现你想要的。 -
htonl()和ntohl()这样的函数呢? -
@AtlasC1 数据对齐!= 字节序
标签: c++ cross-platform portability