C++ volatile:保证 32 位访问?
C++ volatile: guaranteed 32-bit accesses?
在我的 Linux C++ 项目 中,我有一个 硬件内存区域映射到物理地址 space[=41] =] 在执行 mmap.
之后,我使用 uint32_t 指针 访问
应用程序的 release build 崩溃并出现 SIGBUS(总线错误)。
这是因为编译器使用 64 位访问优化了对上述硬件内存的访问,而不是坚持使用 32 位 => 总线错误,硬件内存只能使用32位访问reads/writes.
我将 uint32_t 指针 标记为 volatile。
有效。 这一特定代码部分至少。因为编译器被告知不要进行重新排序。而且大多数时候它必须重新排序才能优化。
我知道 volatile 控制编译器何时访问内存。问题是:volatile 是否也告诉编译器如何访问内存,即完全按照程序员的指示访问它? 我能保证编译器始终坚持对易失性 uint32_t 缓冲区进行 32 位访问吗?
例如volatile 是否也保证编译器也将使用 32 位 reads/writes 访问以下代码片段中对 2 个连续 32 位值 的 2 次连续写入?
void aFunction(volatile uint32_t* hwmem_array)
{
[...]
// Are we guaranteed by volatile that the following 2 consecutive writes, in consecutive memory regions
// are not merged into a single 64-bit write by the compiler?
hwmem_array[0] = 0x11223344u;
hwmem_array[1] = 0xaabbccddu;
[...]
}
我想我回答了我自己的问题,如果我错了请纠正我。
C99 标准草案: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
引述:
“
6 An object that has volatile-qualified type may be modified in ways
unknown to the implementation or have other unknown side effects.
Therefore any expression referring to such an object shall be
evaluated strictly according to the rules of the abstract machine, as
described in 5.1.2.3. Furthermore, at every sequence point the value
last stored in the object shall agree with that prescribed by the
abstract machine, except as modified by the unknown factors mentioned
previously.
”
第 5.1.2.3 节:
“
2 Accessing a volatile object, modifying an object, modifying a file,
or calling a function that does any of those operations are all side
effects, which are changes in the state of the execution environment.
Evaluation of an expression may produce side effects. At certain
specified points in the execution sequence called sequence points, all
side effects of previous evaluations shall be complete and no side
effects of subsequent evaluations shall have taken place. (A summary
of the sequence points is given in annex C.)
5 The least requirements on a conforming implementation are: — At
sequence points, volatile objects are stable in the sense that
previous accesses are complete and subsequent accesses have not yet
occurred.
”
附件C(资料性)序列点:
“
1 The following are the sequence points described in 5.1.2.3:
[…]
— The end of a full expression: an initializer (6.7.8); the expression
in an expression statement (6.8.3); the controlling expression of a
selection statement (if or switch) (6.8.4); the controlling expression
of a while or do statement (6.8.5); each of the expressions of a for
statement (6.8.5.3); the expression in a return statement (6.8.6.4).
”
因此理论上我们可以保证在涉及易变对象的任何表达式的末尾,易变对象是written/read,正如编译器被指示做的那样。
在我的 Linux C++ 项目 中,我有一个 硬件内存区域映射到物理地址 space[=41] =] 在执行 mmap.
之后,我使用 uint32_t 指针 访问应用程序的 release build 崩溃并出现 SIGBUS(总线错误)。
这是因为编译器使用 64 位访问优化了对上述硬件内存的访问,而不是坚持使用 32 位 => 总线错误,硬件内存只能使用32位访问reads/writes.
我将 uint32_t 指针 标记为 volatile。
有效。 这一特定代码部分至少。因为编译器被告知不要进行重新排序。而且大多数时候它必须重新排序才能优化。
我知道 volatile 控制编译器何时访问内存。问题是:volatile 是否也告诉编译器如何访问内存,即完全按照程序员的指示访问它? 我能保证编译器始终坚持对易失性 uint32_t 缓冲区进行 32 位访问吗?
例如volatile 是否也保证编译器也将使用 32 位 reads/writes 访问以下代码片段中对 2 个连续 32 位值 的 2 次连续写入?
void aFunction(volatile uint32_t* hwmem_array)
{
[...]
// Are we guaranteed by volatile that the following 2 consecutive writes, in consecutive memory regions
// are not merged into a single 64-bit write by the compiler?
hwmem_array[0] = 0x11223344u;
hwmem_array[1] = 0xaabbccddu;
[...]
}
我想我回答了我自己的问题,如果我错了请纠正我。
C99 标准草案: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
引述:
“
6 An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3. Furthermore, at every sequence point the value last stored in the object shall agree with that prescribed by the abstract machine, except as modified by the unknown factors mentioned previously.
”
第 5.1.2.3 节:
“
2 Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression may produce side effects. At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place. (A summary of the sequence points is given in annex C.)
5 The least requirements on a conforming implementation are: — At sequence points, volatile objects are stable in the sense that previous accesses are complete and subsequent accesses have not yet occurred.
”
附件C(资料性)序列点:
“
1 The following are the sequence points described in 5.1.2.3:
[…]
— The end of a full expression: an initializer (6.7.8); the expression in an expression statement (6.8.3); the controlling expression of a selection statement (if or switch) (6.8.4); the controlling expression of a while or do statement (6.8.5); each of the expressions of a for statement (6.8.5.3); the expression in a return statement (6.8.6.4).
”
因此理论上我们可以保证在涉及易变对象的任何表达式的末尾,易变对象是written/read,正如编译器被指示做的那样。