Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

volatile variables as argument to function

Having this code:

typedef volatile int COUNT;       

COUNT functionOne( COUNT *number );

int  functionTwo( int *number );

I can't get rid of some warnings..

I get this warning 1 at functionOne prototype

[Warning] type qualifiers ignored on function return type

and I get this warning 2, wherever I call functionTwo with a COUNT pointer argument instead of an int pointer

[Warning] cast discards qualifiers from pointer target type

obviously variables/pointers can't be "cast" to volatile/un-volatile.. but every arguments must be specified as volatile too? so how can I use any library function if it's already defined for non-volatile variable?

EDIT: Using gcc -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wextra -Wstrict-prototypes -Wmissing-prototypes …

EDIT: After Jukka Suomela advice this is a code sample for warning two

typedef volatile int COUNT;       

static int functionTwo(int *number) {
    return *number + 1;
}

int main(void) {
    COUNT count= 10;
    count = functionTwo(&count);
    return 0;
}
like image 981
Hernán Eche Avatar asked Jul 21 '10 20:07

Hernán Eche


People also ask

Can variables be used as function arguments?

No, you will be unable to change the global variable used as an argument of a function parameter. The function parameter gets a copy of the global variable. It itself (the parameter) is a local variable of the function.

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.

Can a function be volatile in C?

Volatile is used in C programming when we need to go and read the value stored by the pointer at the address pointed by the pointer. If you need to change anything in your code that is out of compiler reach you can use this volatile keyword before the variable for which you want to change the value.

Can volatile be placed on class variables and methods?

The volatile keyword cannot be used with classes or methods. However, it is used with variables. It also guarantees visibility and ordering. It prevents the compiler from the reordering of code.


2 Answers

The volatile keyword was designed to be applied to objects that represent storage and not to functions. Returning a volatile int from a function does not make much sense. The return value of a function will not be optimized away (with the possible exception of inlined functions, but that's another case altogether...), and no external actor will be modifying it. When a function returns, it passes a copy of the return value to the calling function. A copy of a volatile object is not itself volatile. Therefore, attempting to return a volatile int will result in a copy, casting it down to a non-volatile int, which is what is triggering your compiler messages. Returning a volatile int* might be useful, but not a volatile int.

Passing an object by value into a function makes a copy of the object, thus using a volatile int as a function parameter necessarily involves a conversion that ignores a qualifier. Passing a volatile by address is perfectly reasonable, but not by value.

According to the C spec, the behavior of volatile is completely implementation-dependent, so YMMV.

Are you using volatile in this way to try to defeat some sort of compiler optimization? If so, there is probably a better way to do it.

Edit: Taking into account the updates to your question, it appears that you may be able to approach this in a different way. If you are trying to defeat compiler optimizations, why not take the direct approach and simply tell the compiler not to optimize some things? You can use #pragma GCC optimize or __attribute__((optimize)) to give specific optimization parameters for a function. For example, __attribute__((optimize(0))) should disable all optimizations for a given function. That way, you can keep your data types non-volatile and avoid the type problems you are having. If disabling all optimizations is a bit too much, you can also turn individual optimization options on or off with that attribute/pragma.

Edit: I was able to compile the following code without any warnings or errors:

static int functionTwo(int *number) {
    return *number + 1;
}

typedef union {
                int i;
    volatile    int v;
} fancy_int;

int main(void) {
    fancy_int count;
    count.v = 10;
    count.v = functionTwo(&count.i);
    return 0;
}

This hack"technique" probably has some kind of odd side-effects, so test it thoroughly before production use. It's most likely no different than directly casting the address to a (int*), but it doesn't trigger any warnings.

like image 57
bta Avatar answered Oct 08 '22 08:10

bta


It's possible that I am way off base here but volatile isn't something normally associated with stack memory region. Therefore I'm not sure if the following prototype really makes much sense.

volatile int functionOne(volatile int number);

I'm not sure how a returned integer can be volatile. What's going to cause the value of EAX to change? The same applies to the integer. Once the value is pushed onto the stack so that it can be passed as a parameter what's going to change its value?

like image 29
torak Avatar answered Oct 08 '22 09:10

torak