1

在我的代码中,我有这样的东西:

#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”{aka 'long unsigned int'} 指针(对齐 4)可能会导致未对齐的指针值 [- Waddress-of-packed-member]

谁能告诉我为什么会这样?获取压缩结构成员的地址当然是危险的。但是整个结构本身应该总是对齐的,不是吗?

4

3 回答 3

1

评论中有答案,但由于作者没有发布,我冒昧地自己发布。所有功劳都归功于@Clifford。

默认情况下,当结构被打包时,编译器也会将结构的对齐方式更改为 1 个字节。但是,对于您的情况,您需要将结构打包并对齐为 32 位无符号整数。这可以通过更改包装属性来完成,如下所示:

#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 平台编译,没有任何警告。

于 2021-08-03T18:43:11.073 回答
1

以我的经验,“打包”结构几乎总是一个坏主意。他们并不总是做人们认为他们会做的事情,他们也可能会做其他事情。根据编译器、目标处理器、选项等,您可能会发现编译器生成的代码使用多字节访问来访问您期望是 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;
};
于 2021-08-16T13:50:20.980 回答
-1

您的打包结构的大小为 3 个字节,其中不能有填充。因此,如果我们要创建一个此类结构的数组,第一个元素具有 4 字节对齐的地址,那么根据数组​​(连续内存)的定义,第二个元素将是三个字节sizeof(struct test_struct_t))。因此,第二个元素将只有单字节对齐 - 因此,通过推论,您的结构的对齐要求是一个字节

在您的 ARM 平台上, aunit32_t需要 4 字节对齐,因此会出现警告。

于 2021-08-03T18:08:29.190 回答