10

Where does a const variable gets stored exactly and how does it behaviour change? Say for example:

const int i=10; // stores where ?  
main()  
{  
   const int j=20; //stores where?   
   return 0;  
}  

If the answer is Code segment then how does the following code work??

main()  
{  
   const int j=20;  
   int *p;  
   p=&j;  
   (*p)++;   
   return 0 ;  
} 

This code works fine... How it is possible to change a read only memory? How does it really get stored? Please explain it to me in detail.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
jack
  • 491
  • 2
  • 7
  • 14
  • Have you checked this: http://stackoverflow.com/questions/3801557/can-we-change-the-value-of-a-constant-through-pointers ? – Bojan Komazec Nov 25 '10 at 09:36
  • 4
    I can assure you that your 2nd code segment is **Undefined Behavior** – SiegeX Nov 25 '10 at 09:41
  • I believe most modern compilers would give a warning when passing through the line "p=&j" warning about Different const qualifiers, because you are assigning a pointer to const int to a pointer to int. So the moral of the story is: Always use -Werror – bone Mar 14 '16 at 09:31

9 Answers9

12

The keyword const indicates a variable that is read-only (i.e., cannot be changed at run-time). It does not indicate a compile-time constant. Therefore, all of the usual attributes of variables apply; specifically, it is allocated addressable storage space.

Unlike with #define, your constant is not necessarily inlined by the compiler. Rather, the compiler will create a symbol corresponding to your const declaration in the object file so that it can be accessed from other code files—remember that const objects have external linkage by default in C (although some compilers will still inline the constant value within the file where it is defined).

The reason the code snippet that you posted "works" is because the unary operator & can be applied to any lvalue, which includes a const object. Though the behavior here is undefined, I suspect that your compiler is detecting this usage and ensuring that your const declaration is given address space, and therefore not inlining it, even within the file it is declared.

EDIT: Also see: http://publications.gbdirect.co.uk/c_book/chapter8/const_and_volatile.html

Let's look at what is meant when const is used. It's really quite simple: const means that something is not modifiable, so a data object that is declared with const as a part of its type specification must not be assigned to in any way during the run of a program. It is very likely that the definition of the object will contain an initializer (otherwise, since you can't assign to it, how would it ever get a value?), but this is not always the case. For example, if you were accessing a hardware port at a fixed memory address and promised only to read from it, then it would be declared to be const but not initialized.

Taking the address of a data object of a type which isn't const and putting it into a pointer to the const-qualified version of the same type is both safe and explicitly permitted; you will be able to use the pointer to inspect the object, but not modify it. Putting the address of a const type into a pointer to the unqualified type is much more dangerous and consequently prohibited (although you can get around this by using a cast). For example...

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • 4
    This is a great answer. I only fully understood what `const` means in C when I came across a variable declared `const volatile` (it was a hardware register). After my initial WTF moment, I realised that `const` just means that **you**, the programmer, promise not to change it. If you expect it to change by other means, you need the `volatile`. But it is not interpreted by the compiler as a compile time constant (as in `C++`, I think). – detly Nov 25 '10 at 09:47
  • 1
    @detly, a const variable can't appear in a place where a constant expression is syntatically required (which indeed is allowed for some of them in C++). The compiler can still consider it as a compile time constant for other purposes -- and probably does. – AProgrammer Nov 25 '10 at 10:18
  • @AProgrammer - indeed, that's a better phrasing. The compiler can't consider it a compile time constant (or runtime constant) if it is also declared volatile, however. – detly Nov 25 '10 at 10:26
7

Modifying your code to print the value:

#include <stdio.h>

main()
{
   const int j=20;
   int *p;
   p=&j;
   (*p)++;
    printf("%d\n", j);
   return 0 ;
}

The above code, when compiled with gcc 4.3.2 at -O1 optimisation or above, results in the output 20 rather than 21. This shows that it hasn't really "worked" - it just appeared to work.

A const qualifier isn't a request to have the variable placed in a particular kind of memory - it's a promise from you to the compiler, that you won't modify that variable by any means. The compiler can rely on your promise to optimise the code that's produced - and if you break your promise, it won't necessarily break in an obvious way, it may just produce strange results.

caf
  • 233,326
  • 40
  • 323
  • 462
4

Per the C standard (n1256 draft):

6.7.3 Type qualifiers
...
3 The properties associated with qualified types are meaningful only for expressions that are lvalues.114)
...
5 If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined. If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined.115)
...
114) The implementation may place a const object that is not volatile in a read-only region of storage. Moreover, the implementation need not allocate storage for such an object if its address is never used.

115) This applies to those objects that behave as if they were defined with qualified types, even if they are never actually defined as objects in the program (such as an object at a memory-mapped input/output address).

In short, a const-qualified object may be stored in a different area from non-const-qualified objects, but not necessarily.

The const qualifier is an instruction to the compiler to reject code that attempts to modify that object directly; attempts to modify the object indirectly (as you do in the second code snippet) results in undefined behavior, meaning any result is possible.

John Bode
  • 119,563
  • 19
  • 122
  • 198
2

I don't know where it is stored, because that's implementation-defined, but your code results in undefined behaviour.

Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
1

It really shouldn't work.

Constants are generally not stored anywhere. They are expanded inline.

It's possible that your compiler is being nice to you and giving you a memory location to modify, but normally that's impossible.

What warnings are you getting? I imagine you must get some...

Mike Caron
  • 14,351
  • 4
  • 49
  • 77
1

Its totally up to the compiler writer what happens to the const, and it will vary according to the optimisation you request.

In your first example the constants are never used so the compiler probably will just ignore them altogether.

In your second example as you use "address off" it must actualy store it somewhere -- probably at the begining of the stack.

As C is designed to replace assembly language instructions, and for writing OS kernal and device driver type code it lets you do all sorts of things and assumes you know what you are doing when you start messing with pointers.

James Anderson
  • 27,109
  • 7
  • 50
  • 78
1

The compiler determines if the address of the constant is ever needed. If it is not, it is (usually) input inline into the code segment because that's (usually) faster than referencing memory.

If the address is needed, then the constant is stored as if it were a non-const variable in the current scope (relatively depending upon compiler). That is, global consts generally get stored in your data segment, function (parameter or declared) consts generally get stored on the stack.

Think of it like a register variable. It's in your CPU's register, if you're familiar with that. It's in your CPU's register until you need its address. Then it's put into addressable space.

The real question is initialization - if you need its address and is therefore actually allocated, then where is it initialized? There's something for you to ponder.

inetknght
  • 4,300
  • 1
  • 26
  • 52
1

The second code shouldn't compile at all. And the compilers I've here agree: gcc gives an error with -pedantic-errors (whose purpose is to turn into error some mandatory diagnostics that historically gcc hasn't considered as error), xlc gives an error as well.

If you want a reference: 6.3.16.1 in C90 standard describes when an assignment is possible:

both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right

and c99 as a similar constraint.

AProgrammer
  • 51,233
  • 8
  • 91
  • 143
1

When you declare (non-extern, non-argument) and initialize variable as const, this means variable is not writable at all. So compiler is free to place it to read only section. Though it may be modifiable physically (if hardware allows it). Or not modifiable, if it protected by MMU or placed in ROM in standalone application.

Standard does not state, what should happen if you try to write const (it is called "undefined behaviour"), so anything may happen: it may be written, not written, cause exception, hang, or something else you cannot imagine. C not so paranoid as, say, Ada, and all unxepected behaviour is up to programmer, not compiler or RTL.

As many stated it is inlined in most cases (if compiler know that to inline), but still retains attributes of variables, such as address (and you can get a pointer), size. If all const reads and pointers to it are eliminated, storage for const will also be eliminated by compiler (if it is static or local) or linker (if it is global).

Note, local pointers may also be eliminated if their locations can be computed in compile time. Also writes to local variables may be eliminated if they're not read after it, so your snippet may have no code at all.

Automatic local variable may be compiled in static storage if compiler prove that only one instance of it is needed. As const is not modifiable it also compiled in static storage, but may be eliminated as stated above.

In all your examples all consts may firstly be put static storage (const section) and then easily eliminated.

Vovanium
  • 3,798
  • 17
  • 23