Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 382
sapi Avatar asked Apr 15 '13 01:04

sapi


People also ask

What is the use of volatile qualifier?

The volatile qualifier declares a data object that can have its value changed in ways outside the control or detection of the compiler (such as a variable updated by the system clock or by another program).

What happens when a variable is declared as volatile?

Volatile is a qualifier that is applied to a variable when it is declared. It tells the compiler that the value of the variable may change at any time-without any action being taken by the code the compiler finds nearby.

What is the purpose of the keyword volatile which is used in declaring some variables in C #?

The volatile keyword is intended to prevent the compiler from applying any optimizations on objects that can change in ways that cannot be determined by the compiler. Objects declared as volatile are omitted from optimization because their values can be changed by code outside the scope of current code at any time.

When variables should not be declared as volatile?

Note, however, that if the DDI data access functions are used to access device registers, it is not necessary to use volatile. When data refers to global memory that is accessible by more than one thread, that is not protected by locks, and that relies on the sequencing of memory accesses.


2 Answers

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!

like image 135
templatetypedef Avatar answered Sep 23 '22 13:09

templatetypedef


The reason for volatile is not to prevent optimisations. That's one of the things that may be done to a volatile variable, but the reason is to indicate to the compiler that the variable may change outside the control of the C "virtual machine", so it shouldn't make too many assumptions about it.

To that end, it's a property of the variable itself rather than the scope of said variable.

If a variable is volatile, passing a pointer to that variable doesn't magically make it non-volatile, it just gives you the address of the volatile variable. That's as it should be.

If you just want to select optimisations based on the scope of a variable, volatile is not the tool for the job. You'll have to find some other (likely non-standard) way, such as disabling that specific warning during the cast with #pragma warning - this of course will depend on your environment.

like image 41
paxdiablo Avatar answered Sep 24 '22 13:09

paxdiablo