Search code examples
cwarningsvolatile

Why is discarding the volatile qualifier in a function call a warning?


(Before I start: I know there are existing questions on this topic, but none I've found answer why this is an issue. I do it regularly and would like to know if I am creating potential problems.)

I'm curious why discarding the volatile qualifier in a function call merits a compiler warning.

The situation is as follows:

volatile uint8_t thingy;
void awesome_function(uint8_t *arg);

awesome_function(&thingy); << warning

Now, my understanding is that the volatile qualifier marks a variable as one that may change in ways outside the compiler's control. Certain optimisations (most importantly, in my experience, the removal of an 'unused' variable) are thus disabled.

However, if I mark a variable as volatile, I am concerned with preventing optimisations in this scope. If I pass the variable down to a function, I am generally happy for standard optimisation to apply within that function.*

This is the case even if the compiler wants to remove the variable from the function (the optimisation I am normally trying to avoid), as even if it does so, it doesn't effect my use of it in this scope; the (result of the) function itself is the sequence point (and lvalue) I am interested in.

So, why is discarding the qualifier with respect to function calls a warning, given that it will not enable reordering in the current scope? Is this because of potential reordering in the called function's scope, which is not allowed for a volatile variable? If so, why is this a problem wrt the current scope?

(* this is normally because such calls are used to start async operations, which will eventually operate on the pointer passed to the function. That function can do whatever it likes with the pointer, provided it eventually updates it as requested. The volatile qualifier is there to alert the compiler that the local variable will change asynchronously.)


Solution

  • The warning here is because the compiler assumes that when you have a pointer to a volatile pointer object, that you honestly believe that the pointee value might change from an outside source. When you pass this pointer into a function that asks for a pointer to a non-volatile object, the compiler warns you that the function call might be optimized in a way that doesn't correctly account for the fact that the object might change.

    The fact that you know for certain that it's okay to do this means that you might want to put in an explicit cast that removes volatile, such as this one:

    awesome_function((uint8_t*) &thingy);
    

    This explicitly tells the compiler "I know that I'm removing volatile here, so don't warn me about it." After all, the whole point of the warning is that you might not have noticed this.

    A good analogue would be to think about const. If you have a pointer to a const object, you are promising not to modify that object through the pointer. If you tried passing this pointer into a function that took a pointer to a non-const object, you would get a warning because the compiler notices that you might accidentally end up changing the value through the function. Putting in an explicit cast would be a way to tell the compiler "yes, I know this pointer shouldn't be used to modify things, but I promise I know what I'm doing."

    Hope this helps!