考虑一个32位系统(例如ARM RISC MCU),如何确保16位变量以原子方式写入/读取?基于this doc,如果我理解正确,16位和8位操作都是原子操作,但仅假设内存对齐。问题是,编译器是否总是将内存与32位字对齐(不包括压缩结构等情况)?这里的基本原理是尽可能使用uint16_t而不是uint32_t,以便在32位和16位平台之间实现更好的代码可移植性,这与在两个平台(16位或32位)上定义不同类型无关。
uint16_t
uint32_t
5anewei61#
编译器可以根据自己的意愿对齐任何(标量)对象,除非它是数组或类似对象的一部分,C语言对此没有任何限制或保证。数组可以保证连续分配,没有填充。并且结构体/联合体的第一个成员可以通过be aligned来保证(因为结构体/联合体的地址可以转换为指向第一个成员类型的指针)。要获得原子操作,如果编译器支持的话,你必须使用类似atomic_uint_fast16_t(stdatomic. h)的东西,否则C中的任何操作都不能被认为是原子的,不管是类型、句点。一个常见的错误是认为“8位拷贝在我的CPU上是原子的,所以如果我使用8位类型,我的代码是可重入的”。这不是,因为uint8_t x = y;不保证在单个指令中完成,也不保证导致原子机器代码指令。即使选择了一条原子指令,你仍然可以从这样的代码中获得实时错误。
atomic_uint_fast16_t
uint8_t x = y;
y
x
正确的实时行为应该是在中断命中之前完全更新x,或者在中断命中之后更新它。
67up9zun2#
我工作的地方与所有相关编译器供应商有一个特殊协议,他们负责通知我们的工具链Maven假设不适用的情况。事实证明这是必要的,因为否则就不能可靠地确定。文档没有说明,标准更没有说明。或者说,这是模具制造人员告诉我的。所以对你来说答案似乎是:问供应商。
2条答案
按热度按时间5anewei61#
编译器可以根据自己的意愿对齐任何(标量)对象,除非它是数组或类似对象的一部分,C语言对此没有任何限制或保证。数组可以保证连续分配,没有填充。并且结构体/联合体的第一个成员可以通过be aligned来保证(因为结构体/联合体的地址可以转换为指向第一个成员类型的指针)。
要获得原子操作,如果编译器支持的话,你必须使用类似
atomic_uint_fast16_t
(stdatomic. h)的东西,否则C中的任何操作都不能被认为是原子的,不管是类型、句点。一个常见的错误是认为“8位拷贝在我的CPU上是原子的,所以如果我使用8位类型,我的代码是可重入的”。这不是,因为
uint8_t x = y;
不保证在单个指令中完成,也不保证导致原子机器代码指令。即使选择了一条原子指令,你仍然可以从这样的代码中获得实时错误。
y
的内容存储在寄存器A中。y
。y
的旧值存储在x
中-耶,这是一条原子指令!x
具有旧的、过时的值。正确的实时行为应该是在中断命中之前完全更新
x
,或者在中断命中之后更新它。67up9zun2#
我工作的地方与所有相关编译器供应商有一个特殊协议,他们负责通知我们的工具链Maven假设不适用的情况。
事实证明这是必要的,因为否则就不能可靠地确定。文档没有说明,标准更没有说明。
或者说,这是模具制造人员告诉我的。
所以对你来说答案似乎是:问供应商。