繁体   English   中英

ARM GCC 打包结构警告地址

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM