gcc 填补的结构(C++)

8qgya5xd  于 2022-11-12  发布在  其他
关注(0)|答案(2)|浏览(244)

我在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字节,这在大多数系统上都是有效的对齐,但是我不知道这是否真的适用于结构体需要它们的元素自然对齐的情况。
这方面的任何帮助都是很好的,但是我总是可以手动地将字节复制到属性中😔。

eyh26e7m

eyh26e7m1#

您有几个选项,通常,您应该选择最适合您需要的选项:
1.如前所述,不要直接从内存中读取/写入内存,而是分别写入每个字段(类似于Java人员的做法)。
这是,我认为,最便携的,但比后来的方法慢得多。
1.对结构重新排序以匹配正常对齐(无论如何都是一个很好的做法)
在您示例中:

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个字节的填充,但不是在中间:)
1.在结构上使用#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...只有那些打算通过通信通道传输或接收的结构体。

0ve6wy6x

0ve6wy6x2#

如果你正在编写跨平台和跨编译器的代码,不要考虑直接读取。只要逐字节读取即可。如果分析表明你需要进一步优化,要么使用底层的流缓冲,要么读入一个字节数组并提取每个片段。
这也消除了系统字节顺序问题。

// 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);
...

同样,在确定存在问题之前,请进行分析。

相关问题