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.
Related
Clarification about terminology used:
For static array I mean array statically memory allocated like: int x[10].
The problem
I need to declare a static array with volatile elements.
If I well understood how volatile qualifier works, it should be:
volatile uint8_t *x; // x is a pointer to volatile uint8_t
uint8_t *volatile x; // x is a volatile pointer to uint8_t
volatile uint8_t *volatile x; // x is a volatile pointer to volatile uint8_t
Ok, but now I need to do the same thing with a static array.
I tried with:
volatile uint8_t x[10]; // Only the pointer is decleared as volatile
uint8_t volatile x[10]; // Same as above
volatile uint8_t *x3[10]; // Casting problems and errors when I do ...
*x3[0] = 1; // ... something like this. Moreover, I do not know if this...
// ... statement declares the uint8_t element as volatile
Thanks!
UPDATE
Ok, as highlighted in the comments I should use:
volatile uint8_t x[10]
As I could understand, the problem is not in the declaration but in the usage of this variable in my code. I pass this element to a function whose prototype is:
static void functionName(uint8_t *buffer, uint32_t size);
I call the function in this way:
functionName(x, 10);
The compiler reports: passing argument 1 of 'functionName' discards 'volatile' qualifier from pointer target type
I can't change the function prototype, how can I solve the problem?
What you have to do to declare a static array of 10 volatile elements of type uint8_tis just:
volatile uint8_t x[10];
Be aware that this is a declaration of an array, which has nothing to see with pointers at this step.
Note: Later in your code, if you use x, it may decay to a pointer to the first volatile element, but in this case this pointer will have a constant value, given at the linking step. The pointed value is obviously volatile.
Stumbled across the problem myself today.
A variable CAN be 'sometimes' volatile.
Being volatile means, that its value can changed outside the program flow. By a parallel thread or an ISR.
Now if the ISR is what changes the value 'unexpectedly', it won't change unexpectedly inside the ISR itself. So for the ISR, the variable is not volatile and disabling compiler optimizations for it is counterproductive.
If I call a function from inside the ISR (and only from there), then the variable is not volatile and I don't want to pass a pointer to volatile, as it would produce inefficient code.
For this case, the solution I found was to have two declarations:
int a[x] = {};
volatile int * b = a;
Now the outside world uses b (globally declared in the header file) and treats the values pointed to by b as volatile, while the ISR (locally) defines both and uses a, treating the values as being not volatile.
Well, this is a very special case. In general, a function only sees the function parameter declaration. Which is either volatile or not, so the funciton will treat a parameter either always as being volatile or always as being not. It cannot automatically switch between two maybe completely differently compiled code blocks depending on the original volatile qualifier state of the passed parameter. Hence the warning.
I have already gone through the answer of question #
What are the differences between const and volatile pointer in C?
I understand the explanation that:
The const modifier means that this code cannot change the value of the variable, but that does not mean that the value cannot be changed by means outside this code.
However, volatile says "this data might be changed by someone else" and so the compiler will not make any assumptions about that data.
Which implies that both type of variables can be changed by external event.
But,then where is the difference in usage of const & volatile?
In C, does compiler optimizations work for const?
volatile and const are different in many ways, they are two distinctively different features.
Declaring a variable just as const never means "I expect this variable to be modified outside the program", I'm not sure where you got that idea from. If you expect a const variable to be modified outside the code, it must be declared as volatile const or the compiler may assume that the variable is never changed.
By default, plain const variables are just like any kind of variable, they simply can't be modified by the program itself.
Just as for plain variables, const variable behavior depends a lot on in which scope they are declared. Most often they are declared at file scope and then they behave as other variables with static storage duration, except they are (likely) saved at a different part of the memory. If they are declared at local scope, they may change from time to time when the function where they reside is called.
So there are plenty of cases where const variables may be optimized. One common optimization is "string pools", where the compiler checks if the same constant string literal appears twice in the code, and then uses the same address for them. Had you expected such strings to be changed from an external source, but didn't declare them as volatile, you'd get strange bugs.
As for volatile variables, they may be modified by external sources, but they may also be modified by the program, unlike const variables.
Objects with const-qualified type are objects like other objects that you may declare in your program, only that you don't have the right to modify them. The underlying object may change for example by aliasing and the compiler has to take care, as for all other objects if such events could have happend. For example
void toto(double const* pi, double* x) {
printf("%g %g\n", *pi, *x);
printf("%g %g\n", *pi, *x);
*x = 5.0;
printf("%g %g\n", *pi, *x);
}
Here it is perfectly ok to call toto with something like toto(&a, &a) and so inside the function pi and x point to the same memory. For the second printf the compiler can assume since it did no store in the mean time that the values of *pi and *x have not changed. But for the third printf it cannot foresee if *pi has changed so it has to reload the value from memory.
volatile is different from that.
void tutu(double volatile* pi, double* x) {
printf("%g %g\n", *pi, *x);
printf("%g %g\n", *pi, *x);
}
Here, for the second printf as before the compiler can assume that *x hasn't changed, but for *pi it must assume that it could have and must reload it from memory. Use cases for volatile are much rarer in daily programmers life, they mainly concern objects that
might represent some hardware address
that could change in an interrupt handler
under some setjmp/longjmp mechanism
or by a different thread
'const' tells the compiler that the value is never changed, not by the program and not by someone else. When something is const, the compiler will optimize the code accordingly, and will usually replace the variable with constants in code. So even if it changes outside, the program may never know.
'volatile', on the contrary tells the compiler that the variable can be changed from the outside anytime, and then the compiler will not perform such optimizations, as putting the var in a register, but will always read it from memory, in case it changed.
Example for demonstrating const
function1()
{
int i = 10;
function2(&i);
}
function2(int const *ptr) // usage of const
{
*ptr = 20; //will cause error; outside function can't be modify the value of i
}
Example for volatile
function1()
{
while(1)
{
i = 20;
print(i);
}
}
function2()
{
i = 20;
while(1)
{
print(i);
}
}
consider these two function. both are seem to be same. for optimisation compiler convert function1 to function2. problem is that if value of i changed by another thread then two function become different, here while loop print value of i and another module change the value of i. so we will not get the value of i as 20 always.
volatile is used to inform the compiler not to optimise the variable.
The const modifier means that this code cannot change the value of the
variable, but that does not mean that the value cannot be changed by
means outside this code.
There are two different ways to apply the const qualifier.
A const-qualified object must not be modified by the program or the program has undefined behavior. A const volatile object can be modified by the OS/hardware/whatever, but not assigned to by the program. For the avoidance of doubt, a const object is one whose definition uses a const type for it.
A pointer-to-const-qualified-type prevents (at compile time) modifications via that pointer, but other pointers to the same object can be used to modify it. Behavior is defined provided the object itself is not const. However, the compiler may still assume that only the program modifies the object, accounting for arbitrary modifications by the OS/hardware/whatever require volatile.
A pointer-to-non-const-qualified-type is exactly the same as the pointer-to-const as far as modifications via other pointers are concerned.
However, volatile says "this data might be changed by something other than code in this program" and so the compiler will not make any assumptions about that data when optimizing.
So the differences are these:
#include <stdio.h>
void some_other_function(const int *);
int main() {
int a = 0;
int volatile b = 0;
int const c = 0;
int const *constptr = &a;
int *ptr = (int*) constptr;
printf("%d\n", a); // compiler can assume a == 0 at this point, and
// replace the code with puts("0") if it wants to
printf("%d\n", b); // compiler cannot assume a value for b, it's volatile[*]
some_other_function(constptr); // defined in another TU
printf("%d\n", a); // compiler can *no longer* assume that a == 0,
// it might have changed
*ptr = 1; // there's another example of a changing, legally
some_other_function(&c);
printf("%d\n", c); // compiler can assume c == 0 because c is const
}
[*] Although I say it "can't assume a value", it may be that some hypothetical C implementation happens to know that there is no OS or hardware mechanism to modify an automatic variable by any means that would require volatile to detect. Especially in this case, where no reference to b has escaped the function. If so, then you might find that the implementation actually can ignore volatile in this particular code, but maybe it treats extern global volatile variables "properly" because it knows that the linker provides a means to map them to the addresses of I/O ports or whatever.
The difference between Volatile and Const can be easily see in bellow case,
1) If you say some variable as Const, it may not be possible to modify by your program.
2) if you say volatile, it is just giving a hint to the compiler not to optimize the code, because the value may be changed from the external threads or other programs.
3) if we define a variable as Const Volatile, that means this variable can not be modified by same program, will not be optimized by compiler and can be modified by external threads or programs.
example:
if i write a function like below,
const freq = 10;
calfreq()
{
return (Const freq * 2);
}
here in this case compiler may optimize the code to
return(20);
all the time.
But here in m y case, freq value may change, because of external hardware / threads / programs
So, if i say Const Volatile, then problem will be fixed.
For a embedded SW project we need to use some const volatile TYPE * pointers. Now we have some calculation functions which are looking like following:
uint8 calc(const volatile uint8 *array, uint8 value) { ... }
The data of both variables is not changing during the function execution.
The calling code looks like following:
const volatile uint8 *array = (const volatile uint8 *)0x00010111;
uint8 value = 8;
uint8 result = calc(array, value);
The question is now, would be there a difference, if we design the calucation functions without volatile arguments:
uint8 calc(const uint8 *array, uint8 value) { ... }
For the call we cast away the volatile:
uint8 result = calc((const uint8 *)array, value);
Pros for the second solution are more flexibility: We can use the function also for non volatile variables. But does it make a difference, if we cast away the volatile and our compiler does some strong optimizations?
You can ALWAYS use the function with non-volatile arguments. Its just that the code in the function handles the given objects as if they were volatile (losing performance on the way, most likely). Its a bit hard to imagine what a function with volatile arguments ("because they might change without notice") could sensibly do. As you write, in your case the data doesn't change anyway, so the most flexible solution is to declare the parameters const and forget about volatile.
And pretty please, use "uint8_t" and not some homegrown type name like uint8 - its in the standard since 1996!
There are two cases: either the function is manipulating hardware registers etc directly. Then you must have volatile in the parameter. Or the function has nothing to do with hardware registers at all. Then it should not have volatile. There is no middle ground between those two cases.
Furthermore, calc((const uint8_t*)array, value); is just a bad, possibly buggy version of
const uint8_t* ptr = array;
calc(ptr, value);
The former form is bad, because the order of evaluation of function arguments is unspecified behavior. The compiler may chose to evaluate the left operand or the right operand first, and you cannot know or assume the order. Since accessing a volatile is a side-effect, your original code can give different results each time the program is built. This is especially problematic (and possibly dangerous) in real time embedded systems.
Therefore it is recommended practice to never access volatile variables inside expressions (see MISRA-C:2004 12.2).
That depends on what really can happen due to volatile-ness.
If the values in this array change during function execution and these changes should be noticed, let them be volatile.
If it doesn't matter, or if the "old" values are more important, omit the volatile.
We are currently developing an application for a msp430 MCU, and are running into some weird problems. We discovered that declaring arrays withing a scope after declaration of "normal" variables, sometimes causes what seems to be undefined behavior. Like this:
foo(int a, int *b);
int main(void)
{
int x = 2;
int arr[5];
foo(x, arr);
return 0;
}
foo is passed a pointer as the second variable, that sometimes does not point to the arr array. We verify this by single stepping through the program, and see that the value of the arr array-as-a-pointer variable in the main scope is not the same as the value of the b pointer variable in the foo scope. And no, this is not really reproduceable, we have just observed this behavior once in a while.
This is observable even before a single line of the foo function is executed, the passed pointer parameter (b) is simply not pointing to the address that arr is.
Changing the example seems to solve the problem, like this:
foo(int a, int *b);
int main(void)
{
int arr[5];
int x = 2;
foo(x, arr);
return 0;
}
Does anybody have any input or hints as to why we experience this behavior? Or similar experiences? The MSP430 programming guide specifies that code should conform to the ANSI C89 spec. and so I was wondering if it says that arrays has to be declared before non-array variables?
Any input on this would be appreciated.
Update
#Adam Shiemke and tomlogic:
I'm wondering what C89 specifies about different ways of initializing values within declarations. Are you allowed to write something like:
int bar(void)
{
int x = 2;
int y;
foo(x);
}
And if so, what about:
int bar(int z)
{
int x = z;
int y;
foo(x);
}
Is that allowed? I assume the following must be illegal C89:
int bar(void)
{
int x = baz();
int y;
foo(x);
}
Thanks in advance.
Update 2
Problem solved. Basically we where disabling interrupts before calling the function (foo) and after declarations of variables. We where able to reproduce the problem in a simple example, and the solution seems to be to add a _NOP() statement after the disable interrupt call.
If anybody is interested I can post the complete example reproducing the problem, and the fix?
Thanks for all the input on this.
That looks like a compiler bug.
If you use your first example (the problematic one) and write your function call as foo(x, &arr[0]);, do you see the same results? What about if you initialize the array like int arr[5] = {0};? Neither of these should change anything, but if they do it would hint at a compiler bug.
In your updated question:
Basically we where disabling interrupts before calling the function (foo) and after declarations of variables. We where able to reproduce the problem in a simple example, and the solution seems to be to add a _NOP() statement after the disable interrupt call.
It sounds as if the interrupt disabling intrinsic/function/macro (or however interrupts are disabled) might be causing an instruction to be 'skipped' or something. I'd investigate whether it is coded/working correctly.
You should be able to determine if it is a compiler bug based on the assembly code that is produced. Is the assembly different when you change the order of the variable declarations? If your debugger allows you, try single stepping through the assembly.
If you do find a compiler bug, also, check your optimization. I have seen bugs like this introduced by the optimizer.
Both examples look to be conforming C89 to me. There should be no observable difference in behaviour assuming that foo isn't accessing beyond the bounds of the array.
For C89, the variables need to be declared in a list at the start of the scope prior to any assignment. C99 allows you to mix assignment an declaration. So:
{
int x;
int arr[5];
x=5;
...
is legal c89 style. I'm surprised your compiler didn't throw some sort of error on that if it doesn't support c99.
Assuming the real code is much more complex, heres some things i would check, keep in mind they are guesses:
Could you be overflowing the stack on occasion? If so could this be some artifact of "stack defense" by the compiler/uC? Does the incorrect value of &foo fall inside a predictable memory range? if so does that range have any significance (inside the stack, etc)?
Does the mcu430 have different ranges for ram and rom addressing? That is, is the address space for ram 16bit while the program address space 24bit? PIC's have such an architecture for example. If so it would be feasible that arr is getting allocated as rom (24bit) and the function expects a pointer to ram (16bit) the code would work when the arr was allocated in the first 16bit's of address space but brick if its above that range.
Maybe you have at some place in your program in illegal memory write which corrupts your stack.
Did you have a look at the disassembly?
Our static analysis tool complains about a "useless type qualifier on return type" when we have prototypes in header files such as:
const int foo();
We defined it this way because the function is returning a constant that will never change, thinking that the API seemed clearer with const in place.
I feel like this is similar to explicitly initializing global variables to zero for clarity, even though the C standard already states that all globals will be initialized to zero if not explicitly initialized. At the end of the day, it really doesn't matter. (But the static analysis tool doesn't complain about that.)
My question is, is there any reason that this could cause a problem? Should we ignore the errors generated by the tool, or should we placate the tool at the possible cost of a less clear and consistent API? (It returns other const char* constants that the tool doesn't have a problem with.)
It's usually better for your code to describe as accurately as possible what's going on. You're getting this warning because the const in const int foo(); is basically meaningless. The API only seems clearer if you don't know what the const keyword means. Don't overload meaning like that; static is bad enough as it is, and there's no reason to add the potential for more confusion.
const char * means something different than const int does, which is why your tool doesn't complain about it. The former is a pointer to a constant string, meaning any code calling the function returning that type shouldn't try to modify the contents of the string (it might be in ROM for example). In the latter case, the system has no way to enforce that you not make changes to the returned int, so the qualifier is meaningless. A closer parallel to the return types would be:
const int foo();
char * const foo2();
which will both cause your static analysis to give the warning - adding a const qualifier to a return value is a meaningless operation. It only makes sense when you have a a reference parameter (or return type), like your const char * example.
In fact, I just made a little test program, and GCC even explicitly warns about this problem:
test.c:6: warning: type qualifiers ignored on function return type
So it's not just your static analysis program that's complaining.
You can use a different technique to illustrate your intent without making the tools unhappy.
#define CONST_RETURN
CONST_RETURN int foo();
You don't have a problem with const char * because that's declaring a pointer to constant chars, not a constant pointer.
Ignoring the const for now, foo() returns a value. You can do
int x = foo();
and assign the value returned by foo() to the variable x, in much the same way you can do
int x = 42;
to assign the value 42 to variable x.
But you cannot change the 42 ... or the value returned by foo(). Saying that the value returned from foo() cannot be changed, by applying the const keyword to the type of foo() accomplishes nothing.
Values cannot be const (or restrict, or volatile). Only objects can have type qualifiers.
Contrast with
const char *foo();
In this case, foo() returns a pointer to an object. The object pointed to by the value returned can be qualified const.
The int is returned by copy. It may be a copy of a const, but when it is assigned to something else, that something by virtue of the fact that it was assignable, cannot by definition be a const.
The keyword const has specific semantics within the language, whereas here you are misusing it as essentially a comment. Rather than adding clarity, it rather suggests a misunderstanding of the language semantics.
const int foo() is very different from const char* foo(). const char* foo() returns an array (usually a string) whose content is not allowed to change. Think about the difference between:
const char* a = "Hello World";
and
const int b = 1;
a is still a variable and can be assigned to other strings that can't change whereas b is not a variable. So
const char* foo();
const char* a = "Hello World\n";
a = foo();
is allowed but
const int bar();
const int b = 0;
b = bar();
is not allowed, even with the const declaration of bar().
Yes. I would advise writing code "explicitly", because it makes it clear to anyone (including yourself) when reading the code what you meant. You are writing code for other programmers to read, not to please the whims of the compiler and static analysis tools!
(However, you do have to be careful that any such "unnecessary code" does not cause different code to be generated!)
Some examples of explicit coding improving readability/maintainability:
I place brackets around portions of arithmetic expressions to explicitly specify what I want to happen. This makes it clear to any reader what I meant, and saves me having to worry about (or make ay mistakes with) precedence rules:
int a = b + c * d / e + f; // Hard to read- need to know precedence
int a = b + ((c * d) / e) + f; // Easy to read- clear explicit calculations
In C++, if you override a virtual function, then in the derived class you can declare it without mentioning "virtual" at all. Anyone reading the code can't tell that it's a virtual function, which can be disastrously misleading! However you can safely use the virtual keyword: virtual int MyFunc() and this makes it clear to anyone reading your class header that this method is virtual. (This "C++ syntax bug" is fixed in C# by requiring the use of the "override" keyword in this case - more proof if anyone needed it that missing out the "unnecessary virtual" is a really bad idea)
These are both clear examples where adding "unnecessary" code will make the code more readable and less prone to bugs.