简体   繁体   中英

C++ volatile: guaranteed 32-bit accesses?

In my Linux C++ project , I have a hardware memory region mapped somewhere in the physical address space which I access using uint32_t pointers , after doing a mmap .

The release build of the application crashes with a SIGBUS (bus error) .

This is happening because the compiler optimizes accesses to the aforementioned hardware memory using 64-bit accesses , instead of sticking to 32-bit => bus error, the hardware memory can only be accessed using 32-bit reads/writes .

I marked the uint32_t pointer as volatile .

It works. For this one specific code portion at least . Because the compiler is told not to do reordering. And most of the time it would have to reorder to optimize.

I know that volatile controls when the compiler accesses the memory. The question is: does volatile also tell the compiler how to access the memory, ie to access it exactly as the programmer instructs ? Am I guaranteed that the compiler will always stick to doing 32-bit accesses to volatile uint32_t buffers?

eg Does volatile also guarantee that the compiler will be accessing the 2 consecutive writes to the 2 consecutive 32-bit values in the following code-snippet using 32-bit reads/writes as well?

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;

    [...]
}

I think I answered my own question, please correct me if I'm wrong.

C99 standard draft : http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf

Quotes:

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.

Section 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 .

Annex C (informative) Sequence points:

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).

So theoretically we are guaranteed that at the end of any expression involving a volatile object, the volatile object is written/read, as the compiler was instructed to do .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM