c - 使用 32 位读取以原子方式读取 4 个字节的数组

标签 c casting atomic

我正在管理一个由 4 个 uint8_t 标志组成的数组。

uint8_t flags[4].

这些标志可以随时被不同的线程改变。

我希望能够通过使用一个原子操作来获取这些标志的快照。 假设我做了以下事情:

uint32_t temp_val = read_atomic32((uint32_t *) &flags[0])

现在我转换回标志数组:

uint8_t *my_flags = &temp_val;
printf("flag zero is %d\n, my_flags[0]);

我怀疑这里有几个问题:

  1. 也许 flags[4] 对于 uint32_t 读取没有对齐,可能会导致非对齐崩溃 或者因为非对齐访问,原子功能可能不会被保证。

  2. 字节序呢?应该出现问题吗?即使我使用的是 uint32_t,我稍后也会将它转换回 uint8_t 数组,我认为内存布局不会因为这个操作而改变——不过,也许我在这里遗漏了一些东西。 我在这里假设,如果我读取一个 4 字节的内存位置,那么无论您的机器是小端还是大端,这些模式在强制转换之前都是相同的。

  3. 有没有更好的方法来管理 uint8_t 的 4 个独立标志,但仍然能够以可移植的安全方式使用一个操作将它们作为一个整体读取?

最佳答案

将你的标志放在 union 中:

union {
  uint8_t  c[4];
  uint32_t t;
} flags;

flags.c[0] = ...;
flags.t = 0xffffffffU;

这会处理对齐问题,您可以使用类型双关通过 t 访问标志,而无需强制转换。根据严格的 ISO C 规则,不太符合犹太洁食标准,但通常可以满足您的要求。

当您分配字面值(如我的示例)或在访问 flags.t 时期望某些值时,字节顺序成为一个问题。只需读取一个值,然后写入一个刚刚读取的值(未修改 - 一点也不浪费!)应该没问题。

关于c - 使用 32 位读取以原子方式读取 4 个字节的数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17557360/

相关文章:

assembly - 在 x86/x86_64 处理器上使用 LFENCE 指令是否有意义?

c - C语言实现文件间回调

使用 getchar() 无法让 EOF 退出 do while 循环

c - 如何在 Shoes 中使用嵌入式 c? ( ruby 串口)

datetime - 如何在 BigQuery SQL 中捕获失败的 CAST 语句?

haskell - 如何将 IORef 与镜头配合使用?

c - 构建 GCC 时的优化

java - 如何在 Java 中将 double 轮次显式转换为 int 轮次?

c++ - C++ 中的函数指针转换

C++11 原子 : why does this code work?