const variables

J

junky_fellow

Hi guys,

Consider the following statements.

const int *ptr; /* ie the contents pointed to by ptr cannot be
changed */

My question is how/who prevents the contents from being modified ?
Is it the C compiler that would give compile time error while trying to
change the contents ? Or is it the implementation that would somehow
prevent the contents from being modified during run time ?

Now consider the following two statements:

const int *ptr; /* line #1 */
int *tmp = ptr; /* line #2 */
*tmp = 100; /* line #3 , Is this valid ? */

Can we change the contents of "tmp" as done is line #3. Will the C
compiler generate warning on line #3. Will this cause some exception
during run time ?

One more question:
const int *ptr = malloc(4 * sizeof(int));
free(ptr); /* gives warning */

While freeing the memory, the compiler generated warning. What is the
reason behind that ? Can't this memory be freed ?


thanks a lot for any help in advance ...
 
E

Eric Sosman

Hi guys,

Consider the following statements.

const int *ptr; /* ie the contents pointed to by ptr cannot be
changed */

Almost: The pointed-to int cannot be changed through ptr,
but could be changed by some other pathway:

int target = 0;
const int *ptr = ⌖
*ptr = 42; /* compile error */
target = 42; /* no problem */
My question is how/who prevents the contents from being modified ?
Is it the C compiler that would give compile time error while trying to
change the contents ? Or is it the implementation that would somehow
prevent the contents from being modified during run time ?

The former. Now, if the target itself is also const, any
attempt to change it produces undefined behavior. For example,
an implementation might place the target in read-only memory
and might cause a trap on any attempt to write to it. Or it
might simply ignore the attempt to write and proceed merrily
and silently on its way. Or the write might succeed, producing
mysteries later on. Or the attempt to write might make demons
fly out of your nose: in theory, at least, Anything Can Happen.
Now consider the following two statements:

const int *ptr; /* line #1 */
int *tmp = ptr; /* line #2 */
*tmp = 100; /* line #3 , Is this valid ? */

Can we change the contents of "tmp" as done is line #3. Will the C
compiler generate warning on line #3. Will this cause some exception
during run time ?

The compiler will object to line #2, because you cannot
"subtract" a qualifier silently. The compiler's objection can
be silenced with a cast:

int *tmp = (int*)ptr;

(Of course, the compiler is permitted to issue warnings for
anything at all, and may still issue a warning for this line.
It must accept the revised code, though, even though it can
reject the original.)

At run time, the behavior depends on what ptr and tmp point
at. If the target is const the behavior of line #3 is undefined,
but if it is non-const the assignment works normally.
One more question:
const int *ptr = malloc(4 * sizeof(int));
free(ptr); /* gives warning */

While freeing the memory, the compiler generated warning. What is the
reason behind that ? Can't this memory be freed ?

When you free() a block of memory, you make it available
for re-use by a subsequent malloc(). Even if free() itself
does not modify the memory block, it exposes the block to
being modified later on. Hence, free(ptr) violates the promise
not to use ptr to modify the memory it points at.

You can still free() the memory, but not by using ptr as
it stands. One way is

free ((void*)ptr);

Even though ptr is const-qualified, (void*)ptr is not. See
the change to line #2 in the earlier example.
 
J

junky_fellow

Eric said:
Almost: The pointed-to int cannot be changed through ptr,
but could be changed by some other pathway:

int target = 0;
const int *ptr = ⌖
*ptr = 42; /* compile error */
target = 42; /* no problem */


The former. Now, if the target itself is also const, any
attempt to change it produces undefined behavior. For example,
an implementation might place the target in read-only memory
and might cause a trap on any attempt to write to it. Or it
might simply ignore the attempt to write and proceed merrily
and silently on its way. Or the write might succeed, producing
mysteries later on. Or the attempt to write might make demons
fly out of your nose: in theory, at least, Anything Can Happen.


The compiler will object to line #2, because you cannot
"subtract" a qualifier silently. The compiler's objection can
be silenced with a cast:

int *tmp = (int*)ptr;

(Of course, the compiler is permitted to issue warnings for
anything at all, and may still issue a warning for this line.
It must accept the revised code, though, even though it can
reject the original.)

At run time, the behavior depends on what ptr and tmp point
at. If the target is const the behavior of line #3 is undefined,
but if it is non-const the assignment works normally.


When you free() a block of memory, you make it available
for re-use by a subsequent malloc(). Even if free() itself
does not modify the memory block, it exposes the block to
being modified later on. Hence, free(ptr) violates the promise
not to use ptr to modify the memory it points at.

You can still free() the memory, but not by using ptr as
it stands. One way is

free ((void*)ptr);

Even though ptr is const-qualified, (void*)ptr is not. See
the change to line #2 in the earlier example.

Thank you Eric for the nice explanation.
 
J

junky_fellow

Eric said:
Almost: The pointed-to int cannot be changed through ptr,
but could be changed by some other pathway:

int target = 0;
const int *ptr = ⌖
*ptr = 42; /* compile error */
target = 42; /* no problem */


The former. Now, if the target itself is also const, any
attempt to change it produces undefined behavior. For example,
an implementation might place the target in read-only memory
and might cause a trap on any attempt to write to it. Or it
might simply ignore the attempt to write and proceed merrily
and silently on its way. Or the write might succeed, producing
mysteries later on. Or the attempt to write might make demons
fly out of your nose: in theory, at least, Anything Can Happen.


The compiler will object to line #2, because you cannot
"subtract" a qualifier silently. The compiler's objection can
be silenced with a cast:

int *tmp = (int*)ptr;

(Of course, the compiler is permitted to issue warnings for
anything at all, and may still issue a warning for this line.
It must accept the revised code, though, even though it can
reject the original.)

At run time, the behavior depends on what ptr and tmp point
at. If the target is const the behavior of line #3 is undefined,
but if it is non-const the assignment works normally.


When you free() a block of memory, you make it available
for re-use by a subsequent malloc(). Even if free() itself
does not modify the memory block, it exposes the block to
being modified later on. Hence, free(ptr) violates the promise
not to use ptr to modify the memory it points at.

You can still free() the memory, but not by using ptr as
it stands. One way is

free ((void*)ptr);

Even though ptr is const-qualified, (void*)ptr is not. See
the change to line #2 in the earlier example.

Thanks Eric for your reply. What I got from your reply is that, if we
are trying to change any const value directly, the compiler will give
error and the code will not be compiled. Secondly, the const value may
be changed indirectly by some other ways, but in that case the
behaviour is undefined ( An implementation may put the const thing in
read only section and while changing it during run time through
indirect ways, it might cause a trap ).

The other thing that I wanted to know whether,
const int *cptr;
int *ptr;
have different types ? Can we convert one type to other without a cast
?

Also, what's wrong in doing,
void *ptr;
const int *ptr1;
ptr = ptr1;
I believe, "void *" is a generic pointer and any pointer type may be
converted to void pointer without cast. Then, why compiler generates
warning while doing "ptr = ptr1" ?

Also, what is the difference between "unqualified type" and "qualified
version of its type" ?
 
E

Eric Sosman

[...]

The other thing that I wanted to know whether,
const int *cptr;
int *ptr;
have different types?

They have different types: "const-qualified pointer to int"
and "pointer to int," respectively.
Can we convert one type to other without a cast?

`cptr = ptr' is fine ("adding" a qualifier is all right),
but `ptr = cptr' is not ("subtracting" a qualifier needs a cast).
Also, what's wrong in doing,
void *ptr;
const int *ptr1;
ptr = ptr1;
I believe, "void *" is a generic pointer and any pointer type may be
converted to void pointer without cast. Then, why compiler generates
warning while doing "ptr = ptr1" ?

Because you're trying to "subtract" the const qualifier.

const void *ptr2;
ptr2 = ptr1;

would be fine.
Also, what is the difference between "unqualified type" and "qualified
version of its type" ?

A "qualified" type has one or more "qualifiers" -- const,
restrict, and/or volatile -- while an unqualified type has none.
A qualified type has the same representation, same universe of
values, same alignment requirements, blah, blah, blah, as the
corresponding unqualified type, but the qualifiers specify
"special handling" of various kinds.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top