c - GCC 的 __attribute__((__packed__)) 是否保留原始顺序?

标签 c gcc compiler-construction networking struct

目的

我正在用 C(特别是 gnu89)编写一个网络程序,我想通过将某个 struct X 重新解释为大字节数组(又名 char),通过网络发送字节,并在另一端将它们重新解释为 struct X。为此,我决定使用 gcc 的 __attribute__((__packed__ ))。我已尽最大努力确保正确完成此操作(即我已考虑字节顺序和其他相关问题)。

问题

除了保证 struct X 尽可能小之外,gcc 是否保证用 __attribute__((__packed__ )) 定义的 struct 保留原始顺序?我进行了大量搜索,但尚未找到任何关于此保证是否存在的文档。

注意事项

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

最佳答案

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

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

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

但是,如果您直接访问结构成员,编译器只会处理错位。您应该永远不要将指针指向压缩结构的成员(除非您知道该成员所需的对齐方式为 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

关于c - GCC 的 __attribute__((__packed__)) 是否保留原始顺序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1756811/

相关文章:

linux - 如何停止 GCC 从 obj 文件中的字符串文字中剥离尾随换行符?

assembly - 玩具编译器的输出语言/格式

c - 达到涉及指针的定义

c - arm cortex m4上的总线错误调试

c - 如何以编程方式编辑路由表

c++ - clang++ 支持 __restrict 吗?

compiler-construction - 多种语言一起编译

mysql - 如何实现连接池?

c - 文件段错误(核心转储)(C-linux)

c - 如何用_mm_clflushopt函数编译程序?错误 : inlining failed