GCC的__attribute __((__ packed__))是否保留原始排序?

25 c compiler-construction networking gcc struct

目的

我正在用C语言编写一个网络程序(特别是gnu89),我希望通过重新解释一个特定的struct X大字节数组(也就是说char),通过网络发送字节,并struct X在另一方面重新解释它们来简化事情.为此我决定使用gcc的__attribute __((__ packed__)).我已尽最大努力确保正确完成(即我已经考虑了字节序和其他相关问题).

除了保证struct X尽可能小,gcc是否保证struct使用__attribute __((__ packed__))定义的保留原始排序?我已经做了相当多的搜索,我还没有找到关于这种保证是否存在的任何文件.

笔记

可以安全地假设发送方和接收方都不会遇到可移植性问题(例如sizeof(int),在服务器上等于sizeof(int)客户端).

Amb*_*jak 39

是的,__attribute__((packed))(不需要第二组下划线)是实现二进制(即非文本)网络协议的正确方法.元素之间不会有差距.

但是你应该明白,packed不仅包装结构,而且:

  • 使其所需的对齐一个字节,和
  • 确保其成员可能因包装错误和结构本身缺乏对齐要求而被正确读取和写入,即其字段的错位由编译器在软件中处理.

但是,如果直接访问struct成员,编译器将只处理错位.您永远不应该指向打包结构的成员(除非您知道成员的必需对齐为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;
}
Run Code Online (Sandbox Code Playgroud)

在x86系统上(不强制执行内存访问对齐),这将产生

y=2, *py=2
Run Code Online (Sandbox Code Playgroud)

正如所料.另一方面,在我的ARM Linux板上,它产生了看似错误的结果

y=2, *py=1
Run Code Online (Sandbox Code Playgroud)


Rob*_*ble 27

假设您正在询问结构成员是否将保留其定义中指定的顺序,答案是肯定的.标准要求后续成员的地址越来越多:

第§6.7.2.1p13节:

在结构对象中,非位字段成员和位字段所在的单元具有按声明顺序增加的地址.

并且packed属性的文档清楚地表明只有填充/对齐受到影响:

packed属性指定变量或结构字段应具有最小可能的对齐 - 变量的一个字节和字段的一个位,除非您使用aligned属性指定更大的值.