Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storage allocation to const variables

I am reading a book which mentions this

If the compiler knows every use of the const, it need not allocate space to hold it. For example:

  1. const int c1=1;
  2. const int c3=my_f(3);
  3. extern const int c4;

Given that values of c3 and c4 are not known as compile time, storage must be allocated for c3 and c4.

I didn't understand any of this. My doubts are:

What does it mean by holding here? Wouldn't it still need to store everything in memory? For c1, wont we have any storage allocation?

Please clear my doubts.

Thank you.

like image 836
bruceparker Avatar asked Jan 14 '12 15:01

bruceparker


3 Answers

c1 is different from the other two constants in that it is initialized with a literal value. This lets compiler put that value everywhere the constant is used, like this:

int x = z + c1;

can be replaced by

int x = z + 1;

This means that the compiler does not need to allocate space and store 1 in it.

c3 and c4 are different: one is calculated using a function, and the other one is supplied from a different compilation unit. This means that the compiler can no longer perform the substitution the way it could with c1: the values of the c3 and c4 are not known to the compiler. Therefore the compiler generates code for

int x = z + c4;

in the same way as if c4 were a variable stored in some place in memory. Since in this case c4 is an external constant, the linker will resolve its location, and fill in the information the compiler is missing (namely, the address of c4) to make the program complete and ready to run.

like image 101
Sergey Kalinichenko Avatar answered Oct 13 '22 06:10

Sergey Kalinichenko


Const has 2 uses - replacement for macros (constant expressions) and also immutable data.

This statement:

const int c1=1;

Is essentially a type-safe version of this:

#define c1 1

Such that this code:

int foo = c1;

Could simply be compiled as:

int foo = 1;

Which is more efficient.

On the other hand, this:

const int c3=my_f(3);

Is being used as an immutable c3. It likely exists in memory, but you can't modify it. It essentially is a safer version of int c3=my_f(3);.

To illustrate this:

int a1[c1];
int a2[c3];

a1 is valid, as the compiler can deduce a1 to be a constant expression. a2 is not, as while c3 is const, it may not be known at compile-time.

C++11 adds the constexpr keyword which is similar to const, although is more strict than const. Only c1 and c2 could be constexpr. c3 could also be, although it would require that my_f is too.

like image 33
Pubby Avatar answered Oct 13 '22 06:10

Pubby


As an Integral Constant Expression, the compiler has every right to use constant folding to remove it from the program. This is only not true if you take it's address. In addition, a modern optimizing compiler can employ LTO, inlining and constant folding to do the same with c3 and c4, if it's possible.

If you do not take the address of a variable, the compiler has no obligation to allocate it if it can generate code with equivalent outcomes, under the as-if rule.

Edit: Constant folding is where the compiler evaluates expressions at compile-time instead of run-time. For example, you can legally do int x[3 + 4]; where 3 + 4 is evaluated at compile-time. Some examples, specifically those involving ICEs, are Standard mandated, but the implementation can perform more if possible. LTO is Link Time Optimization, which is where the compiler performs optimizations across translation units when they are linked together.

This means that the compiler can inline the body of my_f, and then (depending on the body) constant fold it out to make c3 a constant expression, and then constant fold it into wherever it's used and not allocate it. For c4, LTO might yield the value of c4 as a constant expression, in which case it can be constant folded and removed as well.

In C++11 there are constexpr functions which allow much more to be done in this region.

like image 44
Puppy Avatar answered Oct 13 '22 06:10

Puppy