Related
For example, is the following function legal:
struct two_int {
const int a, b;
}
void copy_two(const two_int *src, two_int *dest) {
memcpy(dest, src, sizeof(two_int));
}
It seems like at least some types of modifications of constant-defined values is not allowed, but it is not clear to me if this qualifies.
If the answer is "it is not allowed, in general", I'm also wondering about the special case where dest is newly allocated memory with malloc (and hence hasn't yet been assigned any value), such as:
two_int s = {.a = 1, .b = 2};
two_int *d = malloc(sizeof(two_int));
copy_two(&s, d);
Update: It seems like the latter question seems to answered in the affirmative (it's OK) for the case of a newly malloc'd structure, but the original, more general question still stands, I think.
Use of memcpy for such purposes would have defined behavior only if the actual destination object does not have static or automatic duration.
Given the code:
struct foo { double const x; };
void outsideFunction(struct foo *p);
double test(void)
{
struct foo s1 = {0.12345678};
outsideFunction(&s1);
return 0.12345678;
}
a compiler would be entitled to optimize the function to:
double test(void)
{
static struct foo const s1 = {0.12345678};
outsideFunction(&s1);
return s1.x;
}
On many processors, the only way to load a double with an arbitrary constant is to load its value from object holding that constant, and in this case the compiler would conveniently know an object (s1.x) which must hold the constant 0.12345678. The net effect would be that code which used memcpy to write to s1.x could corrupt other uses of the numeric constant 0.12345678. As the saying goes, "variables won't; constants aren't". Nasty stuff.
The problem would not exist for objects of allocated duration because memcpy requires a compiler to "forget" everything about what had previously been stored in the destination storage, including any "effective type". The declared types of static and automatic objects exist independent of anything being stored into them, and cannot be erased by "memcpy" nor any other means, but allocated-duration objects only have an "effective type" which would get erased.
First note, that almost anything is allowed, in the wider sense of the word: It might simply have undefined behavior. You can take an arbitrary number, reinterpret_cast<> it as an address, and write to that address - perfectly "legal" C++. As for what it does - usually, no guarantees. Here be dragons.
However, as indicated in an answer to this question:
behavior of const_cast in C++
if the structure you're pointing to was not originally defined as const, and simply got const'ified on the way to your code, then const_cast'ing the reference or pointer to it and setting the pointed-to values is required to succeed as you might expect.
I have this very simple test function that I'm using to figure out what's going on with the const qualifier.
int test(const int* dummy)
{
*dummy = 1;
return 0;
}
This one throws me an error with GCC 4.8.3.
Yet this one compiles:
int test(const int* dummy)
{
*(char*)dummy = 1;
return 0;
}
So it seems like the const qualifier works only if I use the argument without casting to another type.
Recently I've seen codes that used
test(const void* vpointer, ...)
At least for me, when I used void *, I tend to cast it to char for pointer arithmetic in stacks or for tracing. How can const void prevent subroutine functions from modifying the data at which vpointer is pointing?
const int *var;
const is a contract. By receiving a const int * parameter, you "tell" the caller that you (the called function) will not modify the objects the pointer points to.
Your second example explicitly breaks that contract by casting away the const qualifier and then modifying the object pointed by the received pointer. Never ever do this.
This "contract" is enforced by the compiler. *dummy = 1 won't compile. The cast is a way to bypass that, by telling the compiler that you really know what you are doing and to let you do it. Unfortunately the "I really know what I am doing" is usually not the case.
const can also be used by compiler to perform optimization it couldn't otherwise.
Undefined Behavior note:
Please note that while the cast itself is technically legal, modifying a value declared as const is Undefined Behavior. So technically, the original function is ok, as long as the pointer passed to it points to data declared mutable. Else it is Undefined Behavior.
more about this at the end of the post
As for motivation and use lets take the arguments of strcpy and memcpy functions:
char* strcpy( char* dest, const char* src );
void* memcpy( void* dest, const void* src, std::size_t count );
strcpy operates on char strings, memcpy operates on generic data. While I use strcpy as example, the following discussion is exactly the same for both, but with char * and const char * for strcpy and void * and const void * for memcpy:
dest is char * because in the buffer dest the function will put the copy. The function will modify the contents of this buffer, thus it is not const.
src is const char * because the function only reads the contents of the buffer src. It doesn't modify it.
Only by looking at the declaration of the function, a caller can assert all the above. By contract strcpy will not modify the content of the second buffer passed as argument.
const and void are orthogonal. That is all the discussion above about const applies to any type (int, char, void, ...)
void * is used in C for "generic" data.
Even more on Undefined Behavior:
Case 1:
int a = 24;
const int *cp_a = &a; // mutabale to const is perfectly legal. This is in effect
// a constant view (reference) into a mutable object
*(int *)cp_a = 10; // Legal, because the object referenced (a)
// is declared as mutable
Case 2:
const int cb = 42;
const int *cp_cb = &cb;
*(int *)cp_cb = 10; // Undefined Behavior.
// the write into a const object (cb here) is illegal.
I began with these examples because they are easier to understand. From here there is only one step to function arguments:
void foo(const int *cp) {
*(int *)cp = 10; // Legal in case 1. Undefined Behavior in case 2
}
Case 1:
int a = 0;
foo(&a); // the write inside foo is legal
Case 2:
int const b = 0;
foo(&b); // the write inside foo causes Undefined Behavior
Again I must emphasize: unless you really know what you are doing, and all the people working in the present and in the future on the code are experts and understand this, and you have a good motivation, unless all the above are met, never cast away the constness!!
int test(const int* dummy)
{
*(char*)dummy = 1;
return 0;
}
No, this does not work. Casting away constness (with truly const data) is undefined behavior and your program will likely crash if, for example, the implementation put const data in ROM. The fact that "it works" doesn't change the fact that your code is ill-formed.
At least for me, when I used void*, I tend to cast it to char* for
pointer arithmetic in stacks or for tracing. How can const void*
prevent subroutine functions from modifying the data at which vpointer
is pointing?
A const void* means a pointer to some data that cannot be changed. In order to read it, yes, you have to cast it to concrete types such as char. But I said reading, not writing, which, again, is UB.
This is covered more in depth here. C allows you to entirely bypass type-safety: it's your job to prevent that.
It’s possible that a given compiler on a given OS could put some of its const data in read-only memory pages. If so, attempting to write to that location would fail in hardware, such as causing a general protection fault.
The const qualifier just means that writing there is undefined behavior. This means the language standard allows the program to crash if you do (or anything else). Despite that, C lets you shoot yourself in the foot if you think you know what you’re doing.
You can’t stop a subroutine from reinterpreting the bits you give it however it wants and running any machine instruction on them it wants. The library function you’re calling might even be written in assembler. But doing that to a const pointer is undefined behavior, and you really don’t want to invoke undefined behavior.
Off the top of my head, one rare example where it might make sense: suppose you’ve got a library that passes around handle parameters. How does it generate and use them? Internally, they might be pointers to data structures. So that’s an application where you might typedef const void* my_handle; so the compiler will throw an error if your clients try to dereference it or do arithmetic on it by mistake, then cast it back to a pointer to your data structure inside your library functions. It’s not the safest implementation, and you want to be careful about attackers who can pass arbitrary values to your library, but it’s very low-overhead.
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.
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.
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.