假设我正在尝试从文件中读取数据。数据存储为二进制数据,可以使用编译器打包扩展轻松读取(为清晰起见,使用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;
};
答案 0 :(得分:1)
我强烈建议不要使用struct
使用协议映射字段1:1。
其中一个原因是允许编译器在字段之间添加填充。
另一个原因是您希望结构对您的处理器有效。希望您更频繁地操作结构中的数据,以便用它执行I / O.
例如,给定一个32位处理器,32位数字效率非常高,但16位处理效率不高。该协议需要16位整数。那么,您是否将结构中的字段映射为16位或32位?
答案:在结构中使用32位字段并编写方法以转换为协议或从协议转换。例如,要从存储器加载16位变量,32位处理器可能必须执行取指和移位,具体取决于16位位于32位寄存器中的位置。如果结构字段是32位,则不需要移位;因此效率更高。
此外,编写协议转换功能可以让您在不改变结构的情况下处理Big-Endian和Little-Endian问题。
答案 1 :(得分:0)
以下是我提出的解决方案:
#include <cstring>
#include <stdint.h>
template <typename T>
struct Fast;
template <>
struct Fast<uint16_t> {
typedef uint_fast16_t Type;
};
template <>
struct Fast<int16_t> {
typedef int_fast16_t Type;
};
template <>
struct Fast<uint32_t> {
typedef uint_fast32_t Type;
};
template <>
struct Fast<int32_t> {
typedef int_fast32_t Type;
};
template <>
struct Fast<uint64_t> {
typedef uint_fast64_t Type;
};
template <>
struct Fast<int64_t> {
typedef int_fast64_t Type;
};
template <typename T>
struct Helper {
typedef typename Fast<T>::Type RetType;
typedef char (VecType)[sizeof(T)];
typedef union { VecType vec; T val; } UType;
};
template <typename T>
struct MakeNum {
typedef typename Helper<T>::RetType RetType;
typedef typename Helper<T>::UType UType;
static RetType Get(const char (&x)[sizeof(T)]) {
UType u;
memcpy( u.vec, x, sizeof(T) );
return u.val;
}
};
#define AddField( type, name ) \
char name ## _[sizeof(type)]; \
typename MakeNum<type>::RetType \
name () const { return MakeNum<type>::Get(name ## _); }
struct S
{
AddField( uint16_t, name1 );
AddField( int32_t, name2 );
AddField( uint16_t, name3 );
};
int main()
{
S s = { 0, 1, 0, 1, 0, 0, 0, 1 };
return s.name1() + s.name2() + s.name3();
}
使用gcc 4.9.1:
生成与此(非可移植)完全相同的代码#include <stdint.h>
struct S2
{
uint16_t v1;
int32_t v2 __attribute__((packed));
uint16_t v3;
};
int main()
{
S2 u = { 256, 256, 256 };
return u.v1 + u.v2 + u.v3;
}