As mentioned in the title, I am little confused if the type-qualifiers
impact the storage location (stack
, bss
etc..) of the declarator.To describe more I am considering the following declarations.
int main()
{
const int value=5;
const char *str= "Constant String";
}
- In the above code, the default
storage-class-specifier
is auto
.
- Hence it is assumed that these constants will be allocated in the
stack-frame
of main
when it is created.
- Generally, the
pointers
to various memory locations in stack have the freedom to modify the values contained in it.
- Hence from the above points it is understandable that, either the
type-qualifier
adds some logic to preserve the constant
nature of the element stored (If so what is it?) or the constants
are stored in a read-only-portion
of memory.Please elaborate on this.
More detailed example
#include <stdio.h>
int main(void)
{
int val=5;
int *ptr=&val;
const int *cptr=ptr;
*ptr=10; //Allowed
//*cptr=10; Not allowed
//Both ptr and cptr are pointing to same locations. But why the following error?
//"assignment of read-only location ‘*cptr’"
printf("ptr: %08X\n",ptr);
printf("cptr: %08X\n",cptr);
printf("Value: %d\n",*ptr);
}
In the above example, both cptr
and ptr
pointing to the same location. But cptr
is pointer to a const type qualified
integer. While modifying the value of cptr
, the compiler throws a error as "assignment of read-only location ‘*cptr’". But I am able to modify the same location with ptr
, as in the output below.Please explain
ptr: BFF912D8
cptr: BFF912D8
Value: 10
In your first example:
int main()
{
const int value=5;
const char *str= "Constant String";
}
Where the variable value
and the string literal will be stored is left to the implementation. All that C standard guarantees is that these will stored in read-only memory which may in text segment, stack or anywhere.
In your second case:
int *ptr=&val;
const int *cptr=ptr;
When you try to modify *cptr
, the compiler doesn't care whether the actual location pointed by cptr
is a read-only or writable. All it cares is that the type qualifier const
using which it thinks the location pointed to by cptr
is read-only.
Another variant:
const int i = 5;
p = &i;
*p = 99;
In this case, the compiler allows modifying a const value through a pointer. But this is undefined behaviour.
I'm not going into the details of your example, but would like to make some general remarks:
C language semantics are enforced by compiler and hardware only up to a certain degree: it's the responsibility of the programmer to avoid undefined behaviour.
Case in point, it's very possible to modify a const-qualified variable of automatic storage duration (stack allocation) by casting away constness from a pointer without getting a segfault (hardware enforcement) or a compiler error (the cast tells it to shut up because you know what you're doing).
Language constraints however will be violated, and code will break in practice because the optimizer will make assumptions which no longer hold.
Then, there's the misconception that the type of the expression used to access the object is relevant to the definedness of an operation - it is not.
The effective typing rules (C99 6.5 §6) essentially make C a strongly typed language with very unsound type system. The type information (among it mutability) is carried by the object (storage location) itself, irrespective of how the location is accessed.
This makes storing into a const-qualified storage location illegal (undefined behaviour) but technically possible (unsound type system). Arbitrary type punning through pointers falls in the same category of operations which violate language semantics, but aren't enforced and thus can lead to strange bugs, eg under the assumption of strict aliasing.