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:
const int c1=1;
const int c3=my_f(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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With