Having this code:
typedef volatile int COUNT;
COUNT functionOne( COUNT *number );
int functionTwo( int *number );
I can\'t get ri
I don't understand why you'd want to have the volatile
qualifier on a function return type. The variable that you assign the function's return value to should be typed as a volatile
instead.
Try making these changes:
typedef int COUNT_TYPE;
typedef volatile COUNT_TYPE COUNT;
COUNT_TYPE functionOne( COUNT number );
COUNT_TYPE functionTwo( COUNT_TYPE number );
And when calling functionTwo()
, explicitly cast the argument:
functionTwo( (COUNT_TYPE)arg );
HTH, Ashish.
If I compile
typedef volatile int COUNT;
static int functionTwo(int number) {
return number + 1;
}
int main(void) {
COUNT count = 10;
count = functionTwo(count);
return 0;
}
using
gcc -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual \
-Wextra -Wstrict-prototypes -Wmissing-prototypes foo.c
I don't get any warnings. I tried gcc 4.0, 4.2, 4.3, and 4.4. Your warningTwo sounds like you are passing pointers, not values, and that's another story...
EDIT:
Your latest example should be written like this; again, no warnings:
typedef volatile int COUNT;
static int functionTwo(COUNT *number) { return *number + 1; }
int main(void) { COUNT count = 10; count = functionTwo(&count); return 0; }
EDIT:
If you can't change functionTwo:
typedef volatile int COUNT;
static int functionTwo(int *number) { return *number + 1; }
int main(void) {
COUNT count= 10;
int countcopy = count;
count = functionTwo(&countcopy);
return 0;
}
Note that any access to a volatile variable is "special". In the first version with functionTwo(COUNT *number)
, functionTwo knows how to access it properly. In the second version with countcopy, the main function knows how to access it properly when assigning countcopy = copy.
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?
It's possible that those who wrote it wanted to be sure that all the operations are atomic, and declared all int variables as volatile (is it a MT application with poor syncronization?), so all the ints from the code are declared as volatile "for consistency".
Or maybe by declaring the function type as volatile they expect to stop the optimizations of the repeated calls for pure functions? An increment of a static variable inside the function would solve it. However, try to guess their original intention, because this just does not make any sense.
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.