arm编译器__packed 与gcc packed

#include <stdio.h>
#include <linux/tcp.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/if_ether.h>

/* ipv4 test vector */
static struct {
        struct ethhdr eth;
        struct iphdr iph;
        struct tcphdr tcp;
}__attribute__((packed)) pkt_v4 = {
        .eth.h_proto = bpf_htons(ETH_P_IP),
        .iph.ihl = 5,
        .iph.protocol = 6,
        .iph.tot_len = bpf_htons(MAGIC_BYTES),
        .tcp.urg_ptr = 123,
};

/* ipv6 test vector */
static struct {
        struct ethhdr eth;
        struct ipv6hdr iph;
        struct tcphdr tcp;
} __attribute__((packed)) pkt_v6 = {
        .eth.h_proto = bpf_htons(ETH_P_IPV6),
        .iph.nexthdr = 6,
        .iph.payload_len = bpf_htons(MAGIC_BYTES),
        .tcp.urg_ptr = 123,
};

int main()
{
  printf("%d,%d,\n",sizeof(pkt_v4),sizeof(pkt_v6));
}

gcc compiler

 

 

#include <stdio.h>
#include <linux/tcp.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include<linux/if_ether.h>

/* ipv4 test vector */
static struct {
        struct ethhdr eth;
        struct iphdr iph;
        struct tcphdr tcp;
} __packed pkt_v4 = {
        .eth.h_proto = bpf_htons(ETH_P_IP),
        .iph.ihl = 5,
        .iph.protocol = 6,
        .iph.tot_len = bpf_htons(MAGIC_BYTES),
        .tcp.urg_ptr = 123,
};

/* ipv6 test vector */
static struct {
        struct ethhdr eth;
        struct ipv6hdr iph;
        struct tcphdr tcp;
} __packed pkt_v6 = {
        .eth.h_proto = bpf_htons(ETH_P_IPV6),
        .iph.nexthdr = 6,
        .iph.payload_len = bpf_htons(MAGIC_BYTES),
        .tcp.urg_ptr = 123,
};

int main()
{
  printf("%d,%d,\n",sizeof(pkt_v4),sizeof(pkt_v6));
}

arm64 compiler

<think>嗯,用户想了解__attribute__((packed))这个属性的作用和用法。我记得这个主要是用在结构体上,用来消除内存对齐的填充字节。不过得确认一下是不是GCC特有的,因为不同的编译器可能有不同的实现,比如MSVC用的是#pragma pack。 首先,应该解释内存对齐的概念。结构体成员通常会按照对齐规则排列,这样可能会在成员之间留下空隙。比如一个char后面跟着一个int,可能会有3字节的填充。使用packed属性后,这些填充会被去掉,结构体变得紧凑,节省内存,但可能影响访问效率。 然后要提到潜在的问题,比如跨平台的可移植性问题,因为其他编译器可能不支持这个属性。还有性能问题,未对齐的内存访问在某些处理器上会导致错误或者速度变慢,尤其是ARM架构可能更敏感。 可能需要举个例子说明,比如定义一个结构体,使用packed后,其大小会变成各成员大小之和,而不使用的话可能有填充。比如包含char和int的结构体,通常大小可能是8字节,而packed后是5字节。 还要注意适用场景,比如网络传输或硬件寄存器映射时,需要精确控制内存布局。但一般情况下不建议滥用,除非确实需要节省内存或者处理特定二进制数据。 用户可能是嵌入式开发者,或者在处理网络协议时需要精确的结构体布局。他们可能遇到了结构体大小不符合预期的问题,或者需要硬件寄存器对齐。需要提醒他们使用时注意对齐访问的问题,避免出现崩溃或性能下降。</think>`__attribute__((packed))` 是 GNU C 编译器(如 GCC)提供的一个扩展属性,主要用于**控制结构体(struct)或联合体(union)的内存对齐方式**。它的核心作用是告诉编译器:“不要在此结构体的成员之间插入任何填充字节(padding),按成员的实际大小紧密排列”。 --- ### **作用和原理** 1. **取消内存对齐优化** 默认情况下,编译器会为结构体成员插入填充字节,使成员在内存中按特定对齐规则排列(例如 4 字节对齐)。这是为了提升 CPU 访问内存的效率(对齐访问通常更快)。 **`packed` 会禁用这一优化**,让结构体成员紧密排列,节省内存空间,但可能导致未对齐的内存访问(在某些硬件上可能引发性能下降或错误)。 2. **典型用途** - 需要硬件寄存器或网络协议的数据格式**精确匹配**时(例如解析网络数据包)。 - 在内存受限的环境中(如嵌入式系统)减少内存占用。 - 处理二进制数据时确保结构体布局外部定义一致。 --- ### **代码示例** ```c #include <stdio.h> // 默认对齐的结构体 struct DefaultStruct { char a; // 1字节 int b; // 4字节(通常需要4字节对齐) short c; // 2字节 }; // 默认对齐后,大小可能为 12 字节(取决于编译器) // 使用 packed 的结构体 struct __attribute__((packed)) PackedStruct { char a; int b; short c; }; // packed 后,大小 = 1 + 4 + 2 = 7 字节 int main() { printf("DefaultStruct 大小: %zu\n", sizeof(struct DefaultStruct)); printf("PackedStruct 大小: %zu\n", sizeof(struct PackedStruct)); return 0; } ``` --- ### **注意事项** 1. **性能影响** 未对齐的内存访问可能导致 CPU 需要多次操作才能读取数据(尤其在 RISC 架构如 ARM 上),甚至触发硬件异常(需结合具体平台判断)。 2. **可移植性** `__attribute__((packed))` 是 GCC 特有语法。其他编译器(如 MSVC)使用 `#pragma pack` 实现类似功能,跨平台代码需做条件编译。 3. **成员访问限制** 对压缩结构体的指针进行类型转换时,可能因地址未对齐导致未定义行为。例如: ```c struct PackedStruct s; int *p = &s.b; // 如果 s.b 的地址未按4字节对齐,访问 *p 可能出错 ``` --- ### **替代方案** - **部分成员对齐控制**:使用 `__attribute__((aligned(n)))` 指定单个成员的对齐方式。 - **编译器指令**:如 `#pragma pack(1)`(MSVC 和 GCC 均支持)。 --- ### **总结** `__attribute__((packed))` 是**以空间换时间的工具**,适用于需要精确控制内存布局的场景,但需谨慎权衡性能和可移植性。在关键代码中,建议添加静态断言(static assert)确保结构体大小符合预期。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值