我在C++中有一个18字节的结构。我想直接从一个文件中读取18个字节的数据到这个结构中。然而,我的C++编译器将结构填充为20字节(4字节对齐(。这对于我的编译器来说相对容易,但我更喜欢使用更可靠的跨平台/跨编译器方法。
这是结构体:
struct Test {
uint8_t a;
uint8_t b;
uint8_t c;
uint16_t d;
uint16_t e;
uint8_t f;
uint16_t g;
uint16_t h;
uint16_t i;
uint16_t j;
uint8_t k;
uint8_t l;
};
我可以在结构的前面添加字节,以保证它是32字节,这在大多数系统上都是有效的对齐方式,但我不知道这是否真的适用于结构需要元素自然对齐的方式。
这方面的任何帮助都会很好,但我最终可能会手动将字节复制到属性中😔.
您有几个选项,像往常一样,您应该选择最适合您需求的选项:
-
如前所述,不要直接从内存中读/写,而是分别写每个字段(Java人会这样做(
我认为这是最可移植的方法,但比后面的方法慢得多。 -
重新排序结构以匹配正常对齐(无论如何都是好的做法(
在您的示例中:
struct Test {
uint8_t a;
uint8_t b;
uint8_t c;
uint8_t f; // moved
uint16_t d;
uint16_t e;
// uint8_t f;
uint16_t g;
uint16_t h;
uint16_t i;
uint16_t j;
uint8_t k;
uint8_t l;
uint16_t spare;
};
注意:它仍然有2个字节的填充,但不在中间:(
- 在结构上使用
#pragma pack(push, 1)
来告诉编译器不要对齐字节
注意:您可能需要放置多个#pragma来支持不同的编译器
#pragma pack(push, 1)
struct Test {
uint8_t a;
uint8_t b;
uint8_t c;
uint16_t d;
uint16_t e;
uint8_t f;
uint16_t g;
uint16_t h;
uint16_t i;
uint16_t j;
uint8_t k;
uint8_t l;
uint16_t spare;
};
#pragma pack(pop)
我想补充一点,正确的对齐有助于CPU更快地处理,因此,您不想在所有结构上强制使用
pack = 1
。。。只有那些打算通过通信信道发送或接收的。
如果您是为跨平台和跨编译器编写,请忘记直接读取。只是逐字节读取。如果评测表明您需要进一步优化,可以使用底层流缓冲,也可以读取字节数组并提取每一块。
这也消除了系统端序问题。
// extract byte values
t.a = f.get();
t.b = f.get();
...
// extract a little-endian value
t.d = f.get();
t.d = t.d | (f.get() << 8);
...
// check for success or failure
if (!f) ...
通过字节数组读取块:
unsigned char buffer[ 18 ];
if (!f.read( (char *)buffer, sizeof(buffer) ))
...
t.a = buffer[0];
...
t.d = buffer[3] | (buffer[4] << 8);
...
再次,在确定存在问题之前先进行简介。