4

Simple question:

Why does the code below work?

int main() {
    const int a = 4;
    const int b = 16;
    const int size = b/a;
    int arr[size] = {0,1,2,3};
    return 0;
}

I thought the size of static arrays have to be defined during compile time, thus only with an "int" literal. In the code above, the code compiles although the size is a calculation. Is this calculation done during compile time?

If yes, maybe my understanding of compile and running is wrong: Compile just goes through the syntax and translates the code to machine code, but does not do any calculations...

Thank you!

Michel H
  • 317
  • 3
  • 10
  • 1
    You might be interessted in `constexpr`: https://en.cppreference.com/w/cpp/language/constexpr and c++ metaprogramming: https://www.boost.org/doc/libs/1_61_0/libs/hana/doc/html/index.html – Sebastian Hoffmann Sep 15 '20 at 10:39
  • Yes, your understanding of compilation is wrong. Compilation tries to do as much optimization as it really can, certainly including calculation of constant expressions. – user207421 Sep 15 '20 at 10:52
  • "_A const integer initialized with a constant can be used in constant expressions_" - which is from [an answer to a question regarding floats](https://stackoverflow.com/questions/30742288/constant-expression-initializer-for-static-class-member-of-type-double/30742473#30742473). It does answer this question indirectly too though. – Ted Lyngmo Sep 15 '20 at 11:00

2 Answers2

4

Is this calculation done during compile time?

Yes, compilers did a lot optimizations and calculations for you, the initialization in your code is ok even without any optimization, and it's the result of pre-calculation of compiler.

Generally, calculation here includes the constexpr, const type declaration and so on, which are already in the definition of language itself(see constant expression).

compile-time const and example

just see the output of the example.

compile-time constexpr and example

The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time.


This is how array can be initialized, an array declaration is as below:

noptr-declarator [ expr(optional) ] attr(optional)

here, expr is:

an integral constant expression (until C++14) a converted constant expression of type std::size_t (since C++14), which evaluates to a value greater than zero

which are all constant expression, which says:

an expression that can be evaluated at compile time.

So, using the so-called pre-calculation to initialize an array is ok.

Here's also a follow-up: there're also a lot of ways to save more calculations and time by let them done during compile time, and they are shown in the link above.


Just to mention something different: As for optimizations, you can see the difference between the assembly codes of version -O0 and -O3 when calculating the sum from 1 to 100, it's a jaw-breaker -- you'll see the result 5050 is in the assembly code in the -O3 version, it's also a kind of compile-time calculation, but not enabled for all kinds of situation.

SHP
  • 305
  • 1
  • 7
  • 2
    Would be nice to have the relevant passages of the standard here – Sebastian Hoffmann Sep 15 '20 at 10:43
  • @SebastianHoffmann I wonder if this version is complete enough. – SHP Sep 15 '20 at 11:10
  • 2
    Be careful here: the question isn't "will some compiler do this calculation at compile-time and end up with a constant for the array size"; it's "does the language definition require this to work". Those are two different things. If it's required to work, optimization settings won't affect it. – Pete Becker Sep 15 '20 at 12:36
  • @PeteBecker, Ah, this is just a follow-up.I'll add them into my answer, thanks. – SHP Sep 15 '20 at 12:40
1

I thought the size of static arrays have to be defined during compile time, thus only with an "int" literal.

The first part is true, but the second part was only true before c++11 (you could also have done const int i = 1 + 2). From c++11, the rules say that the initializing expression is evaluated to see if it yields a constant expression.

There is also the rule that a const integral type is implicitly constexpr (i.e. computed at compile time), so long as the initializing expression is computable at compile time.

So in this expression:

const int size = b/a;

the variable size is required to be computed at compile time, so long as the expression a/b is a constant expression. Since a and b are also const ints that are initialized with a literal, the initialization of size is a constant expression. (Note that removing const from any of the declarations will make size a non-constant expression).

So size is required to be computed at compile time (the compiler has no choice in the matter, regardless of optimizations), and so it can be used as an array dimension.

Here are the complete rules for how this works.

cigien
  • 57,834
  • 11
  • 73
  • 112