[英]Visual C++ equivalent of GCC's __attribute__ ((__packed__))
[英]Does GCC's __attribute__((__packed__)) retain the original ordering?
目的
我正在用C编写一个网络程序(特别是gnu89
),我想通过将某个struct X
重新解释为大字节数组(也就是char
),通过网络发送字节,并将它们重新解释为struct X
来简化事情。另一边。 为此我决定使用gcc的__attribute __((__ packed__))。 我已尽最大努力确保正确完成(即我已经考虑了字节序和其他相关问题)。
题
除了保证struct X
尽可能小,gcc是否保证使用__attribute __((__ packed__))定义的struct
保留原始排序? 我已经做了相当多的搜索,我还没有找到关于这种保证是否存在的任何文件。
笔记
它是安全的假设,发送方和接收方将不会遇到任何的便携性问题(如sizeof(int)
服务器上等于sizeof(int)
客户端)。
是的, __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;
}
在x86系统上(不强制执行内存访问对齐),这将产生
y=2, *py=2
正如所料。 另一方面,在我的ARM Linux板上,它产生了看似错误的结果
y=2, *py=1
假设您正在询问结构成员是否将保留其定义中指定的顺序,答案是肯定的。 标准要求后续成员的地址越来越多:
第§6.7.2.1p13节:
在结构对象中,非位字段成员和位字段所在的单元具有按声明顺序增加的地址。
并且packed属性的文档清楚地表明只有填充/对齐受到影响:
packed属性指定变量或结构字段应具有最小可能的对齐 - 变量的一个字节和字段的一个位,除非您使用aligned属性指定更大的值。
但是,使用__attribute__((__packed__))
并不是一个很好的方法来做你正在做的事情。
基于您要做的事情,我强烈建议您也使用stdint.h中的固定大小的数据类型(即.int32_t,int16_t等)。 使用固定大小的数据类型将阻止您执行以下操作:
struct name
{
short field : 8;
};
我们经常使用这种技术在字节数组和结构之间转换消息,并且从未遇到过它的问题。 您可能必须自己执行字节顺序转换,但字段顺序不是问题。 如果您对数据类型大小有任何疑虑,可以随时指定字段大小,如下所示:
struct foo
{
short someField : 16 __attribute__ ((packed));
};
这可以保证someField将存储为16位,并且不会重新排列或更改以适应字节边界。
是的,C保证不会重新排序struct元素。 (可能有扩展或花哨的优化系统可能会更改此设置,但默认情况下不会更改为gcc。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.