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.
Related
#include <stdio.h>
int main()
{
const int a = 12;
int *p;
p = &a;
*p = 70;
}
Will it work?
It's "undefined behavior," meaning that based on the standard you can't predict what will happen when you try this. It may do different things depending on the particular machine, compiler, and state of the program.
In this case, what will most often happen is that the answer will be "yes." A variable, const or not, is just a location in memory, and you can break the rules of constness and simply overwrite it. (Of course this will cause a severe bug if some other part of the program is depending on its const data being constant!)
However in some cases -- most typically for const static data -- the compiler may put such variables in a read-only region of memory. MSVC, for example, usually puts const static ints in .text segment of the executable, which means that the operating system will throw a protection fault if you try to write to it, and the program will crash.
In some other combination of compiler and machine, something entirely different may happen. The one thing you can predict for sure is that this pattern will annoy whoever has to read your code.
It's undefined behaviour. Proof:
/* program.c */
int main()
{
const int a = 12;
int* p;
p = &a;
*p = 70;
printf("%d\n", a);
return 0;
}
gcc program.c
and run it. Output will be 70 (gcc 4.3)
Then compile it like this:
gcc -O2 program.c
and run it. The output will be 12. When it does optimisation, the compiler presumably loads 12 into a register and doesn't bother to load it again when it needs to access a for the printf because it "knows" that a can't change.
Modifying a const qualified object through a pointer invokes undefined behaviour, and such is the result. It may be something you'd expect from a particular implementation, e.g. the previous value unchanged, if it has been placed in .text, etc.
It does indeed work with gcc. It didn't like it though:
test.c:6: warning: assignment discards qualifiers from pointer target type
But the value did change when executed. I won't point out the obvious no-no...
yes, you can make it done by using such code. but the code do not apply when when a is global (a gcc-compiled program gave me segmentation fault.)
generally speaking, in beloved C, you can almost always find someway to hack things that are not supposed to be changed or exposed. const here being a example.
But thinking about the poor guy(maybe myself after 6 months) maintains our code, I often choose not do so.
Here the type of pointer p is int*, which is being assigned the value of type const int* (&a => address of a const int variable).
Implicit cast eliminates the constness, though gcc throws a warning (please note this largely depends on the implementation).
Since the pointer is not declared as a const, value can be changed using such pointer.
if the pointer would be declared as const int* p = &a, you won't be able to do *p = 70.
This code contains a constraint violation:
const int a = 12;
int *p;
p = &a;
The constraint violated is C11 6.5.16.1/1 "Simple assignment"; if both operands are pointers then the type pointed to by the left must have all the qualifiers of the type pointed to by the right. (And the types, sans qualifiers, must be compatible).
So the constraint is violated because &a has type const int *, which has const as a qualifier; but that qualifier does not appear in the type of p which is int *.
The compiler must emit a diagnostic and might not generate an executable. The behaviour of any executable would be completely undefined, since the program does not comply with the rules of the language.
You cannot change the value of a constant variable by using a pointer pointing to it. This type of pointer is called as Pointer to a constant.
There is also another concept called Constant Pointer. It means that once a pointer points to a memory location you cannot make it point to the another location.
Bad, BAD idea.
Also, the behavior is platform- and implementation-specific. If you're running on a platform where the constant is stored in non-writable memory, this obviously won't work.
And, why on earth would you want to? Either update the constant in your source, or make it a variable.
The problem with changing the value of const variable is that the compiler will not expect that to happen. Consider this code:
const int a = 12;
int * p = &a;
*p = 70;
printf("%d\n", a);
Why would the compiler read a in the last statement? The compiler knows that a is 12 and since it is const, it will never change. So the optimizer may transform the code above into this:
const int a = 12;
int * p = &a;
*p = 70;
printf("%d\n", 12);
This can lead to strange issues. E.g. the code might work as desired in debug builds without optimization but it will fail in release builds with optimization.
Actually a good optimizer might transform the entire code to this:
printf("%d\n", 12);
As all other code before has no effect in the eye of the compiler. Leaving out code that has no effect will also have no effect on the overall program.
On the other hand, a decent compiler will recognize, that your code is faulty and warn you, since
int * p = &a;
is actually wrong. Correct would be:
const int * p = &a;
as p is not a pointer to int, it is a pointer to const int and when declared like that, the next line will cause a hard compile error.
To get rid of the warning, you have to cast:
int * p = (int *)&a;
And an even better compiler will recognize that this cast breaks the const promise and instruct the optimizer to not treat a as const.
As you can see, the quality, capabilities and settings of the compilerwill decide in the end what behavior you can expect. This implies that the same code may show different behavior on different platforms or when using different compilers on the same platform.
If the C standard had defined a behavior for that case, all compilers would have to implement it and no matter what the standard had defined, it would have been hard to implement, putting a huge burden on everyone who wants to write a compiler. Even if the standard had just said "This is forbidden", all compilers would have to perform complex data flow analysis to enforce this rule. So the standard just doesn't define it. It defines that const values cannot be changed and if you find a way to change them anyway, there is no behavior you can rely on.
Yes, you can change the value of a constant variable.
Try this code:
#include <stdio.h>
int main()
{
const int x=10;
int *p;
p=(int*)&x;
*p=12;
printf("%d",x);
}
#include <stdio.h>
int main()
{
const int a = 12;
int *p;
p = &a;
*p = 70;
}
Will it work?
It's "undefined behavior," meaning that based on the standard you can't predict what will happen when you try this. It may do different things depending on the particular machine, compiler, and state of the program.
In this case, what will most often happen is that the answer will be "yes." A variable, const or not, is just a location in memory, and you can break the rules of constness and simply overwrite it. (Of course this will cause a severe bug if some other part of the program is depending on its const data being constant!)
However in some cases -- most typically for const static data -- the compiler may put such variables in a read-only region of memory. MSVC, for example, usually puts const static ints in .text segment of the executable, which means that the operating system will throw a protection fault if you try to write to it, and the program will crash.
In some other combination of compiler and machine, something entirely different may happen. The one thing you can predict for sure is that this pattern will annoy whoever has to read your code.
It's undefined behaviour. Proof:
/* program.c */
int main()
{
const int a = 12;
int* p;
p = &a;
*p = 70;
printf("%d\n", a);
return 0;
}
gcc program.c
and run it. Output will be 70 (gcc 4.3)
Then compile it like this:
gcc -O2 program.c
and run it. The output will be 12. When it does optimisation, the compiler presumably loads 12 into a register and doesn't bother to load it again when it needs to access a for the printf because it "knows" that a can't change.
Modifying a const qualified object through a pointer invokes undefined behaviour, and such is the result. It may be something you'd expect from a particular implementation, e.g. the previous value unchanged, if it has been placed in .text, etc.
It does indeed work with gcc. It didn't like it though:
test.c:6: warning: assignment discards qualifiers from pointer target type
But the value did change when executed. I won't point out the obvious no-no...
yes, you can make it done by using such code. but the code do not apply when when a is global (a gcc-compiled program gave me segmentation fault.)
generally speaking, in beloved C, you can almost always find someway to hack things that are not supposed to be changed or exposed. const here being a example.
But thinking about the poor guy(maybe myself after 6 months) maintains our code, I often choose not do so.
Here the type of pointer p is int*, which is being assigned the value of type const int* (&a => address of a const int variable).
Implicit cast eliminates the constness, though gcc throws a warning (please note this largely depends on the implementation).
Since the pointer is not declared as a const, value can be changed using such pointer.
if the pointer would be declared as const int* p = &a, you won't be able to do *p = 70.
This code contains a constraint violation:
const int a = 12;
int *p;
p = &a;
The constraint violated is C11 6.5.16.1/1 "Simple assignment"; if both operands are pointers then the type pointed to by the left must have all the qualifiers of the type pointed to by the right. (And the types, sans qualifiers, must be compatible).
So the constraint is violated because &a has type const int *, which has const as a qualifier; but that qualifier does not appear in the type of p which is int *.
The compiler must emit a diagnostic and might not generate an executable. The behaviour of any executable would be completely undefined, since the program does not comply with the rules of the language.
You cannot change the value of a constant variable by using a pointer pointing to it. This type of pointer is called as Pointer to a constant.
There is also another concept called Constant Pointer. It means that once a pointer points to a memory location you cannot make it point to the another location.
Bad, BAD idea.
Also, the behavior is platform- and implementation-specific. If you're running on a platform where the constant is stored in non-writable memory, this obviously won't work.
And, why on earth would you want to? Either update the constant in your source, or make it a variable.
The problem with changing the value of const variable is that the compiler will not expect that to happen. Consider this code:
const int a = 12;
int * p = &a;
*p = 70;
printf("%d\n", a);
Why would the compiler read a in the last statement? The compiler knows that a is 12 and since it is const, it will never change. So the optimizer may transform the code above into this:
const int a = 12;
int * p = &a;
*p = 70;
printf("%d\n", 12);
This can lead to strange issues. E.g. the code might work as desired in debug builds without optimization but it will fail in release builds with optimization.
Actually a good optimizer might transform the entire code to this:
printf("%d\n", 12);
As all other code before has no effect in the eye of the compiler. Leaving out code that has no effect will also have no effect on the overall program.
On the other hand, a decent compiler will recognize, that your code is faulty and warn you, since
int * p = &a;
is actually wrong. Correct would be:
const int * p = &a;
as p is not a pointer to int, it is a pointer to const int and when declared like that, the next line will cause a hard compile error.
To get rid of the warning, you have to cast:
int * p = (int *)&a;
And an even better compiler will recognize that this cast breaks the const promise and instruct the optimizer to not treat a as const.
As you can see, the quality, capabilities and settings of the compilerwill decide in the end what behavior you can expect. This implies that the same code may show different behavior on different platforms or when using different compilers on the same platform.
If the C standard had defined a behavior for that case, all compilers would have to implement it and no matter what the standard had defined, it would have been hard to implement, putting a huge burden on everyone who wants to write a compiler. Even if the standard had just said "This is forbidden", all compilers would have to perform complex data flow analysis to enforce this rule. So the standard just doesn't define it. It defines that const values cannot be changed and if you find a way to change them anyway, there is no behavior you can rely on.
Yes, you can change the value of a constant variable.
Try this code:
#include <stdio.h>
int main()
{
const int x=10;
int *p;
p=(int*)&x;
*p=12;
printf("%d",x);
}
This question already has answers here:
Can we change the value of an object defined with const through pointers?
(11 answers)
Closed 5 years ago.
I am able to change the value of const modified variable in gcc but not in other compilers.
I have tried this code on gcc, which updates the value of i and j (11). With an online compiler, I get different values.
#include<stdio.h>
void main() {
const int i=10;
int *j;
j = &i;
(*j)++;
printf("address of j is %p address of i is %p\n",j,&i);
printf("i is %d and j is %d\n",i,*j);
}
Yes, you can do it with a little hack.
#include <stdio.h>
int main(){
const int a = 0;
*(int *)&a = 39;
printf("%d", a);
}
In the above code, a is a const int. With the little hack, you can change the constant value.
Update: Explanation
In the above code, a is defined as a const. For example a has a memory addr 0x01 and therefore &a returns the same. When it is casted with (int *) it becomes another variable referred as a pointer to the const. When it is accessed with * again, the another variable can be accessed without violation of the const policy because it is not the original variable, but the changes are reflected because it is referred as address to the pointer.
This will work on older versions like Borland C++ or Turbo C++, however no one is using it now a days.
It's "undefined behaviour", meaning that based on the standard you can't predict what will happen when you try this. It may do different things depending on the particular machine, compiler, and state of the program.
In this case, what will most often happen is that the answer will be "yes". A variable, const or not, is just a location in memory, and you can break the rules of const and simply overwrite it. (Of course this will cause a severe bug if some other part of the program is depending on its const data being constant!)
However in some cases -- most typically for const static data -- the compiler may put such variables in a read-only region of memory. MSVC, for example, usually puts const static ints in .text segment of the executable, which means that the operating system will throw a protection fault if you try to write to it, and the program will crash.
In some other combination of compiler and machine, something entirely different may happen. The one thing you can predict for sure is that this pattern will annoy whoever has to read your code.
Try this and let me know.
How to modify value of const variable?
No! You shouldn't modify a const variable.
The whole point of having a const variable is to be not able to modify it. If you want a variable which you should be able to modify, simply don't add a const qualifier on it.
Any code which modify's a const forcibly through (pointer)hackery invokes Undefined Behavior.
An Undefined Behavior means that the code is non conforming to the standard specifications laid out by the C standard and hence not a valid code. Such a code can show any behavior and it is allowed to do so.
By defining i as const, you promised not to modify it. The compiler can rely on that promise and assume that it's not modified. When you print the value of i, the compiler can just print 10 rather than loading whatever value is currently stored in i.
Or it can choose to load the value. Or it can cause your program to crash when you try to modify i. The behavior is undefined.
You'll likely see different behavior with gcc depending on the optimization options (-O1, -O3).
Oh, and void main() is incorrect; it should be int main(void). If your textbook tells you to use void main(), you should get a better book.
Take a look at Can we change the value of an object defined with const through pointers?
Long story short, it's an undefined behaviour. It can result dependently on compiler/machine.
You can not modify the value of const variable if you compile this code in gcc it will show
error: invalid conversion from ‘const int*’ to ‘int*’ [-fpermissive]
and show undefined behave
The maiin thing is that we can only modify the variable when we can access the address without address we can't do anything. That's the same thing with Register storage class.
#include <stdio.h>
int main()
{
const int a = 12;
int *p;
p = &a;
*p = 70;
}
Will it work?
It's "undefined behavior," meaning that based on the standard you can't predict what will happen when you try this. It may do different things depending on the particular machine, compiler, and state of the program.
In this case, what will most often happen is that the answer will be "yes." A variable, const or not, is just a location in memory, and you can break the rules of constness and simply overwrite it. (Of course this will cause a severe bug if some other part of the program is depending on its const data being constant!)
However in some cases -- most typically for const static data -- the compiler may put such variables in a read-only region of memory. MSVC, for example, usually puts const static ints in .text segment of the executable, which means that the operating system will throw a protection fault if you try to write to it, and the program will crash.
In some other combination of compiler and machine, something entirely different may happen. The one thing you can predict for sure is that this pattern will annoy whoever has to read your code.
It's undefined behaviour. Proof:
/* program.c */
int main()
{
const int a = 12;
int* p;
p = &a;
*p = 70;
printf("%d\n", a);
return 0;
}
gcc program.c
and run it. Output will be 70 (gcc 4.3)
Then compile it like this:
gcc -O2 program.c
and run it. The output will be 12. When it does optimisation, the compiler presumably loads 12 into a register and doesn't bother to load it again when it needs to access a for the printf because it "knows" that a can't change.
Modifying a const qualified object through a pointer invokes undefined behaviour, and such is the result. It may be something you'd expect from a particular implementation, e.g. the previous value unchanged, if it has been placed in .text, etc.
It does indeed work with gcc. It didn't like it though:
test.c:6: warning: assignment discards qualifiers from pointer target type
But the value did change when executed. I won't point out the obvious no-no...
yes, you can make it done by using such code. but the code do not apply when when a is global (a gcc-compiled program gave me segmentation fault.)
generally speaking, in beloved C, you can almost always find someway to hack things that are not supposed to be changed or exposed. const here being a example.
But thinking about the poor guy(maybe myself after 6 months) maintains our code, I often choose not do so.
Here the type of pointer p is int*, which is being assigned the value of type const int* (&a => address of a const int variable).
Implicit cast eliminates the constness, though gcc throws a warning (please note this largely depends on the implementation).
Since the pointer is not declared as a const, value can be changed using such pointer.
if the pointer would be declared as const int* p = &a, you won't be able to do *p = 70.
This code contains a constraint violation:
const int a = 12;
int *p;
p = &a;
The constraint violated is C11 6.5.16.1/1 "Simple assignment"; if both operands are pointers then the type pointed to by the left must have all the qualifiers of the type pointed to by the right. (And the types, sans qualifiers, must be compatible).
So the constraint is violated because &a has type const int *, which has const as a qualifier; but that qualifier does not appear in the type of p which is int *.
The compiler must emit a diagnostic and might not generate an executable. The behaviour of any executable would be completely undefined, since the program does not comply with the rules of the language.
You cannot change the value of a constant variable by using a pointer pointing to it. This type of pointer is called as Pointer to a constant.
There is also another concept called Constant Pointer. It means that once a pointer points to a memory location you cannot make it point to the another location.
Bad, BAD idea.
Also, the behavior is platform- and implementation-specific. If you're running on a platform where the constant is stored in non-writable memory, this obviously won't work.
And, why on earth would you want to? Either update the constant in your source, or make it a variable.
The problem with changing the value of const variable is that the compiler will not expect that to happen. Consider this code:
const int a = 12;
int * p = &a;
*p = 70;
printf("%d\n", a);
Why would the compiler read a in the last statement? The compiler knows that a is 12 and since it is const, it will never change. So the optimizer may transform the code above into this:
const int a = 12;
int * p = &a;
*p = 70;
printf("%d\n", 12);
This can lead to strange issues. E.g. the code might work as desired in debug builds without optimization but it will fail in release builds with optimization.
Actually a good optimizer might transform the entire code to this:
printf("%d\n", 12);
As all other code before has no effect in the eye of the compiler. Leaving out code that has no effect will also have no effect on the overall program.
On the other hand, a decent compiler will recognize, that your code is faulty and warn you, since
int * p = &a;
is actually wrong. Correct would be:
const int * p = &a;
as p is not a pointer to int, it is a pointer to const int and when declared like that, the next line will cause a hard compile error.
To get rid of the warning, you have to cast:
int * p = (int *)&a;
And an even better compiler will recognize that this cast breaks the const promise and instruct the optimizer to not treat a as const.
As you can see, the quality, capabilities and settings of the compilerwill decide in the end what behavior you can expect. This implies that the same code may show different behavior on different platforms or when using different compilers on the same platform.
If the C standard had defined a behavior for that case, all compilers would have to implement it and no matter what the standard had defined, it would have been hard to implement, putting a huge burden on everyone who wants to write a compiler. Even if the standard had just said "This is forbidden", all compilers would have to perform complex data flow analysis to enforce this rule. So the standard just doesn't define it. It defines that const values cannot be changed and if you find a way to change them anyway, there is no behavior you can rely on.
Yes, you can change the value of a constant variable.
Try this code:
#include <stdio.h>
int main()
{
const int x=10;
int *p;
p=(int*)&x;
*p=12;
printf("%d",x);
}
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.