1

For a embedded SW project we need to use some const volatile TYPE * pointers. Now we have some calculation functions which are looking like following:

uint8 calc(const volatile uint8 *array, uint8 value) { ... }

The data of both variables is not changing during the function execution.

The calling code looks like following:

const volatile uint8 *array = (const volatile uint8 *)0x00010111;
uint8 value = 8;

uint8 result = calc(array, value);

The question is now, would be there a difference, if we design the calucation functions without volatile arguments:

uint8 calc(const uint8 *array, uint8 value) { ... }

For the call we cast away the volatile:

uint8 result = calc((const uint8 *)array, value);

Pros for the second solution are more flexibility: We can use the function also for non volatile variables. But does it make a difference, if we cast away the volatile and our compiler does some strong optimizations?

2
  • probably it won't make any difference. Commented Dec 7, 2012 at 12:25
  • 1
    Probably won't make a difference, but compilers are allowed to do a lot under the hood and the only way to know for sure is to look at the machine code generated. One way to think of casts is that you are telling the compiler "I know better than you"; in this case you don't. Commented Dec 7, 2012 at 12:51

3 Answers 3

3

You can ALWAYS use the function with non-volatile arguments. Its just that the code in the function handles the given objects as if they were volatile (losing performance on the way, most likely). Its a bit hard to imagine what a function with volatile arguments ("because they might change without notice") could sensibly do. As you write, in your case the data doesn't change anyway, so the most flexible solution is to declare the parameters const and forget about volatile.

And pretty please, use "uint8_t" and not some homegrown type name like uint8 - its in the standard since 1996!

Sign up to request clarification or add additional context in comments.

4 Comments

Sure, I was only to lazy to write it ;) - My colleagues are only worried about, that the compiler (for tricore) is doing some strange optimizations.
As you are not doing anything undefined here, the compiler is not allowed to do too strange things. All demons that will fly out your nose will be your own code's ;).
This answer appears to be written as if the function parameters are volatile but the function is called with non-volatile arguments. However, the question asks about modifying the function parameters to be non-volatile but calling it with arguments that are volatile but cast to non-volatile.
@EricPostpischil True, I just wanted to correct the OPs view on his initial function behaviour. He already aimed in on hhe better solution so no need to repeat this point explitictly.
1

There are two cases: either the function is manipulating hardware registers etc directly. Then you must have volatile in the parameter. Or the function has nothing to do with hardware registers at all. Then it should not have volatile. There is no middle ground between those two cases.

Furthermore, calc((const uint8_t*)array, value); is just a bad, possibly buggy version of

const uint8_t* ptr = array;
calc(ptr, value);

The former form is bad, because the order of evaluation of function arguments is unspecified behavior. The compiler may chose to evaluate the left operand or the right operand first, and you cannot know or assume the order. Since accessing a volatile is a side-effect, your original code can give different results each time the program is built. This is especially problematic (and possibly dangerous) in real time embedded systems.

Therefore it is recommended practice to never access volatile variables inside expressions (see MISRA-C:2004 12.2).

3 Comments

I disagree here. The evaluation of the expression "array" does not pose an access to the volatile object. If you have objects (hardware registers) which are sensible to their mutual access order (e.g. interrupt flag and acknowledge flag) then volatile won't save your ham either - modern instruction-reordering deep pipelines destroy any attempt to impose the program flow as on the "hypothetical ideal C machine" which the standard defines. Just waded through a code review with exact these properties in question on an embedded PowerPC.
@slartibartfast You are not correct, the volatile object is accessed as it is copied into the non-volatile function parameter. Also, my remarks are not related to multi-processing or thread-safety at all, I don't know where you got that from. They are related to real time performance, hence the text "real time" in my post.
I can't see where the volatile object (which "array" points to) is accessed in the call. Also, I did not mention multithreading or multiprocessing either. It is a single thread of execution inside a reordering pipeline which breaks what the programmer (and the standard) intended under the use of "volatile". And how such a problem relates only to real time programming, is beyond me. Either you get correct code or you don't?
0

That depends on what really can happen due to volatile-ness.

If the values in this array change during function execution and these changes should be noticed, let them be volatile.

If it doesn't matter, or if the "old" values are more important, omit the volatile.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.