![](/img/trans.png)
[英]warning: taking address of packed member of 'struct details' may result in an unaligned pointer value [-Waddress-of-packed-member]
[英]ARM GCC Address of packed struct warning
在我的代码中,我有这样的东西:
#include <stdint.h>
typedef struct __attribute__((packed)) {
uint8_t test1;
uint16_t test2;
} test_struct_t;
test_struct_t test_struct;
int main(void)
{
uint32_t *ptr = (uint32_t*) &test_struct;
return 0;
}
当我使用 arm-none-eabi-gcc 编译它时,我收到警告
.\test.c:11:2:警告:将打包的“test_struct_t”指针(对齐 1)转换为“uint32_t”{又名“long unsigned int”}指针(对齐 4)可能会导致未对齐的指针值 [- Waddress-of-packed-member]
谁能告诉我为什么会这样? 获取打包结构成员的地址当然是危险的。 但是整个结构本身应该总是对齐的,不是吗?
评论里有答案,不过作者没发,我冒昧自己发一下。 所有的功劳都归功于@Clifford。
默认情况下,打包结构时,编译器还会将结构的 alignment 更改为 1 个字节。 但是,对于您的情况,您需要将结构打包并对齐为 32 位无符号 integer。这可以通过如下更改打包属性来完成:
#include <stdint.h>
struct __attribute__((packed, aligned(sizeof(uint32_t)))) TestStruct {
uint8_t test1;
uint16_t test2;
};
struct TestStruct test_struct;
int32_t* p = (int32_t*)(&test_struct);
此编译适用于 ARM 平台,没有任何警告。
根据我的经验,“打包”结构几乎总是一个坏主意。 他们并不总是做人们认为他们做的事情,他们也可能做其他事情。 根据编译器、目标处理器、选项等,您可能会发现编译器生成的代码使用多字节访问来访问您希望是 16 位或 32 位访问的内容。
硬件寄存器总是会在微控制器上正确对齐。 (位域可能是另一回事,但您在这里没有使用位域。)但可能存在间隙或填充。
尝试使用指向 uint32_t 的指针访问它的整个想法是错误的。 不要像这样通过指针转换访问数据 - 事实上,如果您看到指针转换,请高度怀疑。
那么如何获得与硬件结构完全匹配的结构呢? 你明确地写出来,并使用编译时检查来确定:
#pragma GCC diagnostic error "-Wpadded"
struct TestStruct {
uint8_t test1;
uint8_t padding;
uint16_t test2;
};
_Static_assert(sizeof(struct TestStruct) == 4, "Size check");
填充是显式的。 任何错误都会被编译器捕获。
如果您真的非常想要中间有一个未对齐的 16 位字段,并且您在阅读数据表时没有犯错怎么办? 使用位域:
#pragma GCC diagnostic error "-Wpadded"
struct TestStruct2 {
uint32_t test1 : 8;
uint32_t test2 : 16;
uint32_t padding : 8;
};
_Static_assert(sizeof(struct TestStruct2) == 4, "Size check");
明确地放入填充。 告诉编译器抱怨缺少填充,并检查大小。 编译器不对额外的微秒工作收费。
如果您真的、真的、真的需要将它作为 uint32_t 来访问怎么办? 你使用一个联合来进行类型双关(虽然不是用 C++):
union TestUnion {
uint32_t raw;
struct TestStruct2 s;
};
您的打包结构的大小为 3 个字节,其中不能有填充。 因此,如果我们要创建此类结构的数组,第一个元素具有 4 字节对齐的地址,那么根据 arrays(连续内存)的定义,第二个元素将为三个字节( sizeof(struct test_struct_t)
)从那个。 因此,第二个元素将只有一个字节alignment - 因此,通过推导,您的结构的 alignment 要求是一个字节。
在您的 ARM 平台上, unit32_t
需要 4 个字节 alignment,因此出现警告。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.