I think I have a tricky question, but I'm sure you will be able to help me. Let's say I have a function like this:
char my_function (int example);
I use this function in multiple cases, sometimes the argument it receives is a volatile variable and sometimes a non-volatile variable. That cause some warnings when I compile my code that can be easily removed by using casts, but I want to understand which is the safer scenario and why.
Scenario 1:
Prototype: char my_function (int example);
int a;
volatile int b;
my_function (a); // Everything is fine.
my_function ((int)b); // Avoided the warning, by casting the variable and saying it's no longer volatile.
Scenario 2:
Prototype: char my_function (volatile int example);
int a;
volatile int b;
my_function(b); // Everything is fine.
my_function((volatile int)a); // Avoided the warning, by casting 'a' saying that now it's volatile.
I understand how volatile modifier works, I mostly use it because I program micro-controllers and I need to ensure that some of my variables are never optimized out when they are hardware modified. I am a bit confused about casting the volatile modifier and that is why I want to understand which is the safer scenario apart from just removing the warning.
It really depends on what my_function
does with its argument.
Remember that volatile
prevents certain optimizations - predominantly it forces the variable to be re-read every time it is referenced. Thus this code
volatile int a;
int b;
// ...
b = a + 1;
b = a + 2;
will read a
for each statement and, as a
may have changed values between them, give the correct result.
When you pass a volatile
into a function as a parameter, you only get one read
of the variable. This may then be used multiple times within the function (effectively losing the volatile
nature).
Remember that C is pass-by-value. When you invoke the function as
my_function((int)b); // b is declared volatile
The compiler generates code to read b
once in the calling code, and push the value it read onto the stack (usually), then invoke my_function
. This copy is then referenced within my_function
as example
, and no matter how often you reference example
you will always get the same value (even if the original b
variable has since changed many times).
That might be exactly what you want - take a snapshot of the variable and do several computations on its value.
If it's not what you want, you need to consider passing in a pointer with the appropriate volatile
qualifications.
char my_function( volatile int *example);
And call it thus:
my_function(&a);
my_function(&b);
Then reference *example
inside my_function
.
The cast doesn't actually do anything. In the call my_function (b); the code reads the volatile int b. That's where the "volatile" matters, during the read. The result of the read is already an int and not a volatile int. There are no volatile int values. Even if there were volatile int values, passing it to my_function would convert it to plain int, just as the cast does.
It may be that the compiler assumes that passing a volatile int variable to a function is something dangerous worth a warning, and by adding a cast to int you indicate that you know what you are doing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With