Generally, especially when optimization is turned on, a compiler will attempt to make constants as efficient as possible. For example, if you write x = 3*4 + 5
, the compiler would reduce this to 17 at compile time rather than putting 3, 4, and 5 in the compiled program.
Small constants that are used directly are often encoded into immediate fields of instructions.
If the compiler cannot put a constant into the immediate field of an instruction, it will generally seek to store it in read-only memory.
However, the example you give makes that difficult for the compiler. The code in your example:
- Defines a
const
object inside a routine (as opposed to at file scope).
- Takes the address of the object.
If you merely defined a const
object and never took its address, the compiler could store the constant in the read-only data section.
However, since you take the address of the object, there is a problem. Routines can be called recursively. (Your program does not call main
recursively, but the compiler is designed to support recursive calls, so the issues discussed here apply to its design.) Whenever a routine is called recursively, new instances of the objects defined in it must be created (in the C model of computation). If the address of a const
object were not taken, the compiler could optimize this by using the same read-only memory for all instances of the object—since their values never change, nobody could tell they were just one instance instead of multiple copies.
However, different instances of an object can be distinguished by their addresses. Since you take the address of the object, the compiler wants to create actual different instances of it. That is difficult to do in read-only memory. Programs do not normally maintain a stack for read-only memory, so the compiler does not have a convenient way to track the multiple instances that would have to be created for objects in read-only memory. (It would be difficult to maintain a stack for read-only memory. If what is on the stack can be different at different times, then the memory for that stack has to change. So, even if only read-only objects are on a stack, the stack itself cannot be read-only.)
So, in this case, the compiler places your const
object on the regular stack.
Of course, that is not a behavior you may rely on. Attempting to change the value of an object that is defined const
has behavior not defined by the C standard. Even though it appears to “work” in this case, it is possible that, in more complicated programs, the compiler might transform your program with various optimizations with the result that your program would fail when trying to modify a const
object like this. For example, printf("%d", *y)
could print “2” because the memory y
points to has been changed to 2, while printf("%d", x)
could print “1” because x
is known (in the C model of computation) to be a constant 1.