3

Working on creating my own programming language, which notably supports pointers and constants, I wonder how constants are stored in memories in languages such as C? I've read on StackOverflow that they were stored in read-only memories at runtime, but I don't understand how this could be possible since the following code compiles and executes well:

#include <stdio.h>

int main (int argc, char ** argv) {
  const int x = 1;

  int *y;
  y = &x;

  *y += 1;

  printf("x = %d\n", x); // Prints: 2
  printf("y = %d\n", *y); // Prints: 2

  return 0;
}

Here, I define a constant called x and make a pointer from it so I can modify its value. This means x cannot be stored in a read-only memory.

So, I really wonder how constants are stored at runtime?

8
  • 4
    They're stored in RAM. On a PC, it doesn't store it in flash or anything like that. The const tells the compiler you intend not to change it. However, if you "cheat" and use a pointer you can change it, but I'll bet you saw a warning to that effect when you compiled. The warning you get with gcc is, warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers] y = &x; So the const is ignored in that case. Commented Apr 8, 2018 at 14:50
  • 1
    You showed the source code for a program, but that proves nothing. Did you compile and run it? If so, and it ran, that would only prove the specific implementation you compiled and ran it on does not store x in read-only memory in this instance (and making certain assumptions about how the C model of computation was implemented). Commented Apr 8, 2018 at 14:50
  • 1
    keyword const don't mean constant but read only... yeah ok it's miss leading. warning: assigning to 'int *' from 'const int *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers] when I compile your code... standard doesn't not describe this kind of specification, compiler are free to do what they like. Commented Apr 8, 2018 at 14:51
  • 1
    depends on the level of optimization. with -O0 gcc puts it on stack. Commented Apr 8, 2018 at 15:00
  • 1
    This is not a valid C program and it does not compile well for any reasonable definition of "well". Commented Apr 8, 2018 at 15:17

4 Answers 4

5

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.

Sign up to request clarification or add additional context in comments.

1 Comment

That is a really good discussion of the caveats associated with const and why you should not cheat.
2

You have discovered a sad fact about undefined behavior in C.

"Compiles and executes well" does not (not not not) prove that the code is legal and correct!

If you cheat, and try to write to a const-qualified location, anything can happen: you can get an error message, it can seem to work, or quietly do something almost or completely unlike what you expected.

When you said

y = &x;

your compiler should have warned you, something along the lines of "warning: assigning to 'int *' from 'const int *' discards qualifiers". (That's exactly what my compiler said.)

So, yes, a compiler is perfectly within its rights to store unmodifiable constants in the text segment, or some other section of read-only memory. If that means programs like yours fail, that's perfectly fine.

But there's one more point. The "constant" you declared, const int x = 1, was a local variable. So there needs to be a new instance of it for each call to the function, meaning that it's likely to be stored on some kind of a stack. So that means the compiler probably isn't going to put x in read-only memory, because I've never heard of read-only memory on the stack.

If you make x a global variable, by declaring it outside of main(), or if you put static in front of it, it won't get stored on any stack, and it's much more likely to be stored in read-only memory. In fact, when I make either of those two changes to your code, not only do I get the same warning when I compile it, but when I run the program, it crashes with "Bus error".

Comments

1

AFAIK, how they are stored is an implementation detail depending on the compiler. However, it is generally stored in text section.

By the way, const just apply you to be warned by the compiler if the const variable is wanted to change.

4 Comments

Does that mean that the code I wrote could crash depending on the platform and/or compiler?
@ClementNerma: Absolutely.
@ClementNerma if you were writing this code on an embedded system, it's possible the assumption of the compiler (depending upon the tool) would assume that the value is in ROM. Your program could crash, or it may simply malfunction due to it not doing what you think you told it to do.
To clarify, the "text section" is where the executable code is. Using "text" that way is rooted in computer science a long time ago.
0

A const object in C is a variable the compiler doesn't allow assignments to. As such, it can be applied the address operator to get its address, or can be used as if it where a variable (or even an lvalue ---of course, of type const) but you cannot modify it (at least with normal assignment procedures). The compiler is allowed (for static consts) to store them in read-only memory, but that's not imposed by the standard. This is the quick answer. For a more detailed, I refer you to the standard.

In the case you post, when you use the &x expression, you get a const int* value, that is automatically converted to a int * pointer (probably you are getting a warning for that and that warning is being ignored)

$ make pru
cc -O -pipe  pru.c  -o pru
pru.c:7:5: warning: assigning to 'int *' from 'const int *' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
  y = &x;
    ^ ~~
1 warning generated.

For legacy code compatibility reasons, this is treated as a warning and not an error, so you are free to act in consequence (you haven't done this in this case :) )

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.