Reputation: 79
This is the source of the common "discarded const qualifier at assignment" error. However, I don't understand why it is illegal to do so?
Consider this code,
int sum_array(const int *a, int n){
int sum, *i;
sum = 0;
for(i = a; i<a+n; i++)
sum += *i;
return sum;
}
Obviously I can do the same operation using i = 0
and comparing a + i < a+n
; however, it doesn't make sense to me why simply copying the address of a variable into another variable is illegal?
Typically the const variable indicates that the value of a variable cannot be changed. E.g. const int x = 7, here we declare that the value of x should not be changed from 7.
However, with const pointers, creating the "potential" to change the variable is also illegal. I.e. i = a does not change the value of what a points to, what would truly be "illegal" would be *i = 0, however, i = a is still illegal because it gives us the potential to change a.
I know you can just answer me with "because the language was created that way", I'm just wondering if there's anything I'm missing here.
Upvotes: 1
Views: 177
Reputation: 222362
The question proposes that, given const int *a
, int *i = a;
could be allowed and a subsequent *i = 0;
would be disallowed (“illegal”).
This is not feasible because it requires the compiler to track information about the source of the data in i
. At the point where *i = 0;
appears, the compiler has to know that i
contains a value resulting from the initialization from a
.
We could do that in very simple code. But consider that the code may be very complicated, with loops, branches, and function calls. At the point where *i = 0;
appears, the compiler generally cannot know whether i
still holds the address from a
or has been changed to something else. (I expect this is equivalent to the Halting Problem and hence is logically impossible in general).
C uses types to manage this. When a
is a pointer to const
, it may only be assigned to a pointer to const
(unless overridden by explicit cast). So i
is required to be a pointer to const
, which enables the compiler to know that the thing it points to should not be modified.
Upvotes: 1
Reputation: 36391
const
serves two purposes:
in the contract of the function call (here int sum_array(const int *a, int n)
) it means that the argument a
will not be used by the function to modify the contents pointed by a
(a
is not constant, it is a pointer to things considered constant). Then caller knows that the data will not be modified through call and the compiler must enforce it as it can:
inside the function definition, implementor is then protected against accidental modification of contents pointed by a
. ie. if he tries to write something like *a = someValue;
then compiler will complain as the contract is violated. But then it also verifies that this contract is respected in anyway. Thus, any derived variable from a
that may give access to the same data must be considered as const
or the contract will be violated. Then writing int *p = a
is a clear violation of that, because p
is not a pointer to const data, which would let you write *p = someValue
to modify data.
Be aware that const
doesn't mean that data is const, only that through the pointer it is forbidden to modify the data. Then:
const int *a...
int *p = a;
is forbidden but
int *a...
const int *p = a;
is correct because in that case you have a pointer which let you modify data through it and you construct a derived one that restrict access to the same data through the derived pointer. Data is modifiable through a
but not through p
. Restricting is never dangerous, opening could.
Of course you can enforce the dangerous derivation by using cast (which lets you remove const
) but I would not recommend doing so. Advice, if you are tempted doing so, please refrain yourself, think again, if after that you really want to do so, let things go hang for a full night and think about it again the day after... Recipe is:
const *a...;
int *p = (int *)a; // "seriously refrain" advice
Upvotes: 2
Reputation: 183251
The primary purpose of const
is to enlist the compiler's help in ensuring that you don't accidentally modify a given object. It uses the type system for this. You can actually circumvent it if you want, by writing an explicit cast; but usually you don't want that, because if you wanted that then that usually means you didn't really want the const
to begin with.
Upvotes: 2