0

I have a struct like this:

typedef struct _HEADER_IO
    {
        uint8_t field1 : 2;
        uint8_t field2 : 4;
        uint8_t field3 : 1;
        uint8_t field4 : 1;
        uint16_t field5;
        uint8_t field6;
    } HEADER_IO;

It's basicly a message header that will be sent over tcp. The server reads this so that it knows what data follows in the buffer. However for some reason intead of the size being 4 bytes (2+4+1+1 first byte + 2 bytes from field 5 + 1 byte field 6) the size is 6 bytes.

Looking it up in memory view it is:

XX AA XX XX XX AA

Instead of:

XX XX XX XX

Where AA are never set no matter what I do. This is a problem because I am planning for the header to be send() to a server and the extra bytes are included making the server interpret the header wrong. What am I doing wrong?

4

2 回答 2

1

一般来说,将位域用于此类事情是个坏主意。由于您无法事先确切知道这些位最终会出现在哪个字节中,并且存在填充和对齐问题。

在我看来,最好“承认”这样一个事实,即您需要对外部表示进行更多控制,而不是 C 结构给您的控制,然后手动进行。您当然可以将结构保留为内存(内部)表示。

基本上,您会编写如下函数:

size_t header_serialize(unsigned char *buf, size_t max, const HEADER_IO *header);

它的工作是在 的内存中buf构建代表 的正确字节序列header

为了澄清(基于评论),目的是从 中读取字段header,而不仅仅是例如

memcpy(buf, header, sizeof *header);  /* DON'T DO THIS! */

相反,您应该从header. 这样,无论编译器对header.

于 2012-04-19T13:18:40.943 回答
0

在标准 C 中,您无法避免结构成员可以在它们之间插入填充的事实。在处理之前,您必须编写一个函数来解码数据并将其存储在您的结构中。这是因为在某些架构上,未对齐的内存访问(从未对齐的指针读取,例如,4 个字节)非常昂贵,C 会自动填充您的结构以避免成本。没有打开或关闭该功能的标准方法。

例如,在 GCC 中,您可以__attribute__((packed))在 struct 定义之后添加,Visual Studio 有一些GCC 也支持的#pragma命令(参见http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html),但要注意总体而言这是非标准的。

由于您的评论提到它是一个 Windows 程序,因此如果您在 struct 定义之前添加它可能会起作用:

#pragma pack(push,1)

而这之后:

#pragma pack(pop)

虽然编写代码以更手动地解码标头会更便携,但上述方法应该更快。

于 2012-04-19T13:01:09.710 回答