如何解决 C 中的指针转换以避免未对齐的内存访问?

How to work around pointer casting in C to avoid unaligned memory access?

我最近了解到指针转换可能会触发未对齐的内存访问,例如在

void test_func(uint8_t *data) {
        /*The rest of the code removed for clarity*/
    uint32_t value = *((uint32_t *) data);
}

但是如果我真的需要投指针,我该如何解决呢?在上面的示例中,如果我必须将 data 作为 uint32_t 访问,但仍想避免未对齐的内存访问怎么办?

How to work around pointer casting in C to avoid unaligned memory access?

你不能(例如,在 x86-64 上,未对齐的内存访问是可能的,但速度很慢;在 Arduino-s 上也可能是这种情况)。

另请参阅 _Alignas and _Alignof C11 的运算符。

在许多实现中,可以从 intptr_t 来回转换指针,然后您可以玩按位技巧。

In the example above, what if I have to access data as an uint32_t but still want to avoid unaligned memory access?

您需要确保 test_func 调用者 正在传递对齐良好的指针。

Frama-C, the Clang static analyzer, or perhaps, at end of spring 2021, Bismon

等工具可为您提供帮助

您可以 #include <assert.h> 并添加,作为您 test_func 的第一条语句: assert((intptr_t)data % sizeof(uint32_t) == 0); ;参见例如assert(3).

How to work around pointer casting ... to avoid unaligned memory access?

使用 memcpy(&value, data, sizeof value); 代替 *((uint32_t *) data) 传输数据。一个好的编译器会产生高效的代码。

uint8_t data[4] = { 1,2,3,4};
uint32_t value;
memcpy(&value, data, sizeof value);

... 或确保 uint8_t value[] 通过 *alloc()

unionalignas 对齐
union {
  uint8_t data[4];
  uint32_t d32;
} x;
...  
test_func(x.data) {

#include <stdalign.h>
alignas(uint32_t) uint8_t data[4] = { 1,2,3,4};
test_func(data);

uint8_t *data = malloc(sizeof *data * 4);
...
test_func(data);
free(data);