Purpose
我正在用 C 编写一个网络程序(具体来说gnu89
)我想通过重新解释某个特定的内容来简化事情struct X
作为大字节数组(又名char
),通过网络发送字节,并将它们重新解释为struct X
另一方面。为此我决定使用 gcc 的 __attribute__((__packed__ ))。我已尽最大努力确保正确完成此操作(即我已经考虑了字节顺序和其他相关问题)。
Question
除了保证这一点之外struct X
尽可能小,gcc 是否保证struct
用 __attribute__((__packed__ )) 定义保留原始顺序?我已经进行了大量搜索,但尚未找到任何有关此保证是否存在的文档。
Notes
可以安全地假设发送者和接收者都不会遇到可移植性问题(例如sizeof(int)
在服务器上等于sizeof(int)
在客户端)。
Yes, __attribute__((packed))
(不需要第二组下划线)是实现二进制(即非文本)网络协议的正确方法。元素之间不会有间隙。
不过你应该明白packed
不仅打包结构,还:
- 使其所需的对齐方式为一个字节,并且
- 确保其成员(可能因包装和结构本身缺乏对齐要求而导致错位)被正确读取和写入,即其字段的错位由编译器在软件中处理.
However,如果直接访问结构成员,编译器只会处理错位。你应该永远不要创建指向打包结构成员的指针(除非您知道成员所需的对齐方式为 1,例如 char 或其他打包结构)。以下 C 代码演示了该问题:
#include <stdio.h>
#include <inttypes.h>
#include <arpa/inet.h>
struct packet {
uint8_t x;
uint32_t y;
} __attribute__((packed));
int main ()
{
uint8_t bytes[5] = {1, 0, 0, 0, 2};
struct packet *p = (struct packet *)bytes;
// compiler handles misalignment because it knows that
// "struct packet" is packed
printf("y=%"PRIX32", ", ntohl(p->y));
// compiler does not handle misalignment - py does not inherit
// the packed attribute
uint32_t *py = &p->y;
printf("*py=%"PRIX32"\n", ntohl(*py));
return 0;
}
在 x86 系统上(不强制内存访问对齐),这将产生
y=2, *py=2
正如预期的那样。另一方面,例如在我的 ARM Linux 板上,它产生了看似错误的结果
y=2, *py=1
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)