tags:

views:

454

answers:

4

Sorry if this is simple, my C++ is rusty.

What is this doing? There is no assignment or function call as far as I can see. This code pattern is repeated many times in some code I inherited. If it matters it's embedded code.

*(volatile UINT16 *)&someVar->something;

edit: continuing from there, does the following additional code confirm Heaths suspicions? (exactly from code, including the repetition, except the names have been changed to protect the innocent)

if (!WaitForNotBusy(50)) 
    return ERROR_CODE_X;

*(volatile UINT16 *)& someVar->something;

if (!WaitForNotBusy(50)) 
    return ERROR_CODE_X;

*(volatile UINT16 *)& someVar->something;
x = SomeData;
+9  A: 

I think the author's intent was to cause the compiler to emit memory barriers at these points. By evaluating the expression result of a volatile, the indication to the compiler is that this expression should not be optimized away, and should 'instantiate' the semantics of access to a volatile location (memory barriers, restrictions on optimizations) at each line where this idiom occurs.

This type of idiom could be "encapsulated" in a pre-processor macro (#define) in case another compile has a different way to cause the same effect. For example, a compiler with the ability to directly encode read or write memory barriers might use the built-in mechanism rather than this idiom. Implementing this type of code inside a macro enables changing the method all over your code base.

EDIT: User sharth has a great point that if this code runs in an environment where the address of the pointer is a physical rather than virtual address (or a virtual address mapped to a specific physical address), then performing this read operation might cause some action at a peripheral device.

Heath Hunnicutt
Futhermore a macro could make it more obvious what is going on... (#define READ_MEMORY_BARRIER ...)
Aaron
First step should be to evaluate whether it actually does create a memory barrier. That does seem to be the intent, but volatile variables on many platforms are only ordered with respect to other volatile variables. Even if it works for this embedded platform it may not work for another; I'd look for a better, more portable solution for creating barriers.
Dan Olson
I don't thnk it has anything to do with memory barriers, It is an embedded platform, and it probably maps a variable to some IO.
Nemanja Trifunovic
Your edit is the more likely explanation in an embedded system (as tagged), even if I understood the first answer I'd say it was unlikely.
Clifford
+9  A: 

So here's a long shot.

If that address points to a memory mapped region on a FPGA or other device, then the device might actually be doing something when you read that address.

sharth
Why a long shot? I think that is a perfectly logical explanation. +1
Nemanja Trifunovic
The original question lacked a lot of the clarifications that make it clear this is happening on an embedded system, etc.
Conrad Meyer
A: 

Generally this is bad code.

In C and C++ volatile means very few and does not provide implicit memory barrier. So this code is just quite wrong uness it is written as

memory_barrier();
*(volatile UINT16 *)&someVar->something;

It is just bad code.

Expenation: volatile does not make variable atomic!

Reed this article: http://www.mjmwired.net/kernel/Documentation/volatile-considered-harmful.txt

This is why volatile should almost never be used in proper code.

Artyom
Eh!? What does that mean?
Clifford
+17  A: 

This is a fairly common idiom in embedded programming (though it should be encapsulated in a set of functions or macros) where a device register needs to be accessed. In many architectures, device registers are mapped to a memory address and are accessed like any other variable (though at a fixed address - either pointers can be used or the linker or a compiler extension can help with fixing the address). However, if the C compiler doesn't see a side effect to a variable access it can optimize it away - unless the variable (or the pointer used to access the variable) is marked as volatile.

So the expression;

*(volatile UINT16 *)&someVar->something;

will issue a 16-bit read at some offset (provided by the something structure element's offset) from the address stored in the someVar pointer. This read will occur and cannot be optimized away by the compiler due to the volatile keyword.

Note that some device registers perform some functionality even if they are simply read - even if the data read isn't otherwise used. This is quite common with status registers, where an error condition might be cleared after the read of the register that indicates the error state in a particular bit.

This is probably one of the more common reasons for the use of the volatile keyword.

Michael Burr
Thanks, marked this one as answer because I think it's the clearest and most complete response.
BioBuckyBall