开发者

slightly weird C++ code

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)

i开发者_StackOverflowf (!WaitForNotBusy(50)) 
    return ERROR_CODE_X;

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

if (!WaitForNotBusy(50)) 
    return ERROR_CODE_X;

*(volatile UINT16 *)& someVar->something;
x = SomeData;


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.


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.


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜