13

I want to know about const internals in C and C++ . How does the compiler impose "constantness" ?

Mehdi Charife
  • 722
  • 1
  • 7
  • 22
mousey
  • 11,601
  • 16
  • 52
  • 59
  • 5
    Are you specifically interested in C or C++, because there can be a difference. For example, marking a method const in C++ have no equivalent construct in C. – Skurmedel May 11 '10 at 17:17
  • can some one help me how compiler creates const. I just want to know the internals and not how const works in C or C++ – mousey May 11 '10 at 18:35
  • 1
    (you even get points for doing it) – Adam May 11 '10 at 21:08

6 Answers6

26

In general const is 100% compiler. When you declare something const, the compiler places restrictions on what it will let you write. It won't let you assign to const scalar, assign through a const reference or or pointer, or invoke a non-const function of const object.

There is no guarantee that the compiler will arrange any sort of runtime protection.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
  • 3
    Excellent answer. For anyone interested in further reading, I suggest the C++ FQA's section on const correctness: http://yosefk.com/c++fqa/const.html – Eli Courtwright May 11 '10 at 17:37
  • 4
    @Eli how on earth did someone vote up a FQA link... Better read on the FAQ about const-correctnes: http://www.parashift.com/c++-faq-lite/const-correctness.html . Less rants, more substance – Johannes Schaub - litb May 11 '10 at 18:23
  • 2
    @Johannes: I actually disagree with the FQA's underlying conclusions about C++ and I happily use C++ in my day job, but I feel that the FQA can be insightful and thought-provoking, and reading it has helped me understand some of the problems I run into when coding C++ far better than the FAQ. Plus, the FQA links directly to the FAQ in each question, so it's easy to see the original answers. I probably should have added a disclaimer that the FQA is probably not a good resource for novice programmers, who should definitely stick with the FAQ instead. – Eli Courtwright May 11 '10 at 19:38
11

const keyword in C and C++ has two different semantic meanings.

(1) It can declare the constness of an object

const SomeType t;

In the above case object t is a non-modifiable object. The compiler will do its best to prevent you from modifying it by observing the const-correctness rules (which are not the same in C and C++). The const-correctness rules are enforced only conceptually, at the language level, which means that there are ways to circumvent these rules, and which also means that constness of an object will not be necessarily implemented at physical level. I.e. there's no guarantee that the object will be ultimately placed in read-only memory.

It is important to note that this kind of constness is not removable in a sense that any attempts to modify the above object by casting away the constness lead to undefined behavior (excluding possible mutable members in C++).

(2) It can declare constness of an access path to an object

const SomeType *p;

The above p is declared as a pointer-to-const. This does not necessarily mean that the object p is pointing to is a constant object (as defined by the first kind of const above). It might easily be a non-constant one, in which case it is perfectly legal to cast away the constness from the above access path and modify the object, although it is generally not a good programming practice. In other words, constness of an access path is potentially removable.

Taking the above into account, the following declaration

const int* const* const* const p = 0;

includes two different kinds of const: the very last const declares the constness of the object p (first kind), while the rest of const declare the constness of various levels of access path represented by p (second kind).

P.S. As a [possibly unrelated] side note, it is probably worth noting that the term constant has drastically different meanings in C and C++. In C++ constants are objects declared as const. In C constants are literals. Objects declared as const are not constants in C terminology.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • I barely recall some information I read long time ago that there is a difference between C and C++ in case of built in integral types, as in C++, (unlike in C) const can define a compile-time constant and not necessarily a variable. I don't remember enough to add a perfectly correct standalone answer, but if I'm right maybe this information could be added here :) – Maciej Hehl May 11 '10 at 17:50
  • @Maciej H: Yeah, I did an answer on that http://stackoverflow.com/questions/2308194/shall-i-prefer-constants-over-defines/2308364#2308364, but it didn't want to go into that issue here. – AnT stands with Russia May 11 '10 at 18:35
  • 1
    While trying to understand declarations like `const int* const* const* const p = 0;` this "rule" comes handy - [Basically ‘const’ applies to whatever is on its immediate left (other than if there is nothing there in which case it applies to whatever is its immediate right)](http://duramecho.com/ComputerInformation/WhyHowCppConst.html) – Lazer May 12 '10 at 15:47
  • @Lazer So, essentially, that could have been written `int const *const *const *const p = 0;` – Mateen Ulhaq May 31 '19 at 09:35
5

In addition to the compile-time enforced immutability provided by using the const keyword that other answers to your question have already mentioned, using it sometimes allows the compiler to place such data in the read-only section of a binary and memory. According to Section 2.4.2 "Forever const" in Ulrich Drepper's article How To Write Shared Libraries doing so potentially allows programs to (1) use less resources and (2) start up faster.

Note that casting away the constness of data in such read-only areas of memory results in the undefined behavior, as usual.

Void - Othman
  • 3,441
  • 18
  • 18
2

When the compiler is compiling the code, it computes the type of each expression so it can type-check them and emit code correctly (such as warning when you try to store an int in a pointer, or properly converting an integer to a double). const-ness can be considered part of the type. Since it has the type information for the expression, it can check the type of the lvalue (left-hand side of the assignment) and throw an error if it has 'const' in its type.

Michael Ekstrand
  • 28,379
  • 9
  • 61
  • 93
1

In C, the const keyword will make a variable immutable, meaning that it cannot be modified.

Usually, this is a compile-time distinction and has no effect on runtime modification of a variable. For instance, a const variable can be indirectly modified using a pointer to the same memory address.

In C++, the const keyword takes on more than one meaning.

For instance, a class member function can be "const", meaning that it is not allowed to modify the state of a class instance.

As in C, a variable declared const can also be modified indirectly using a pointer, but also by using the "mutable" keyword or the const_cast<> operator.

Tom
  • 18,685
  • 15
  • 71
  • 81
1

This is actually a very complicated thing in an optimizing compiler. It starts out simple, though.

When you declare a variable with the const keyword (let's just ignore pointers because they can be const or point to const or both) the compiler remembers that no code should be changing that variable (almost). If the compiler sees code that changes a const variable then it considers that an error (or occasionally only worthy of a warning, but for simplicity sake I'll ignore it). The compiler also assumes that no code that it cannot see (right now anyway {code in other .c files or possibly library or .s or .asm files) will change the const variable (unless it is const volatile in which case it will assume that it could change at any moment, but will still enforce not letting your code change it -- this is useful for memory mapped SFR [special function registers] that are used to read a device's state, but can't be written to. Remember that c and c++ are used for OS and embedded programming).

The assumption that a variable will not change under some or all circumstances allows the compiler's optimization routines to do things that it otherwise wouldn't be able to do. This means stuff like placing the literal value of a variable into the instruction stream rather than loading the variable's address and then loading the variable's value. It can also assume that if it loaded that if:

extern const int foo; // note that the value isn't visible, so a load is necessary
...
extern int baz(int, int);
...
int bar(int x, int y) {
   int m, n;
   int r = x / foo; // this would require loading the value of foo from RAM
   m = baz(r, y); // the compiler normally has to assume that a function could change a global
   n = m + r + foo; // but since the global foo is const it shouldn't be able to be changed
                    // by the call to baz and does not need to be reloaded
   return n;
}

An executable file (or other object file) may have a section (.rodata) that has only constants in it. In many cases the OS may enforce not allowing a program to write to this data (or it may even be in ROM in some cases). This section may also contain versions of non-const variables which are used for initialization, since it may have any constant in it, not just constants declared as const.

So in C const mainly just tells the compiler to tell you that you've screwed up and are trying to change something that should not have been changed. It is allowed to make some assumptions based on it, though.

In C++ it gets more complicated. I don't remember all of the details, but I do recall that you can overload a function name based on if a value you pass to it is const or not, which can be useful.

nategoose
  • 12,054
  • 27
  • 42