5

I'm just wondering whether sentences like const int N=10 will be executed at compilation time. The reason I'm asking is because that the following code will work.

int main()
{
  const int N=10;
  int a[N]={};
  return 0;
}    

But this one wouldn't.

int main()
{
  int N=10;
  int a[N]={};
  return 0;
}
andy90
  • 525
  • 5
  • 19
  • Related to this question [Does “int size = 10;” yield a constant expression?](http://stackoverflow.com/q/21273829/1708801) that I have an [answer on](http://stackoverflow.com/questions/21273829/does-int-size-10-yield-a-constant-expression/21273849#21273849) – Shafik Yaghmour Nov 20 '14 at 19:38
  • Short answer: in this particular situation yes. – 101010 Nov 20 '14 at 19:38
  • An array must be declared as a set size. That is why the array index must be defined as a constant and the reason why the first piece of code works and not the second. – Sean Cox Nov 20 '14 at 19:39

4 Answers4

7

The compiler must generate code "as if" the expression was evaluated at compile time, but the const itself isn't sufficient for this. In order to be used as the dimension of an array, for example, expression N must be a "constant integral expression". A const int is a constant integral expresion only if it is initialized with a constant integral expression, and the initialization is visible to the compiler. (Something like extern int const N;, for example, can't be used in a constant integral expression.)

To be a constant integral expression, however, the variable must be const; in your second example, the behavior of the compiler and the resulting program must be "as if" the expression were only evaluated at runtime (which means that it cannot be used as the dimension of an array). In practice, at least with optimization, the compiler likely would evaluate N at compile time, but it still has to pretend it can't, and refuse to compile the code.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • That's for the answer. A further question is that is the first example supported by all kinds of compilers? Will 'a[N]' declared in the first example be put in the stack? – andy90 Nov 20 '14 at 20:22
  • The first example is required to be supported. You can define local arrays, as long as the dimensions are "integral constant expression". Since `int const N = 10;` makes `N` and integral constant expression, it can be used when defining an array where `N` is in scope and visible. (How a compiler does this is its business, but in practice, all local arrays will be on the stack.) – James Kanze Nov 21 '14 at 10:32
2

The compiler will probably evaluate both of the examples you provided at compile time, since even though the int N = 10; isn't const, you're not changing it anywhere and you're only assigning a constant value to it, which means the compiler can optimize this.

I recommend you take a look at the constexpr keyword introduced in C++11, which is exactly about being able to evaluate things at compile time.

Jakub Arnold
  • 85,596
  • 89
  • 230
  • 327
  • But I got the following error message when compiling the second example with icc: `error: variable "a" may not be initialized int a[N]={};`. – andy90 Nov 20 '14 at 19:51
  • @andy90 see http://stackoverflow.com/questions/21273829/does-int-size-10-yield-a-constant-expression for more details on why you're getting the error – Jakub Arnold Nov 20 '14 at 19:53
  • `constexpr` doesn't change anything in this case. – James Kanze Nov 20 '14 at 20:00
  • @JamesKanze I never said it does anything in this case. I only mentioned that it is related to evaluating things at compile time. – Jakub Arnold Nov 20 '14 at 20:03
1

Compilers will resolve const variables to literals at compile time (and also const expressions, see constant folding). The reason that the first method works is that compiler knows how much space to allocate (10*sizeof(int)) to a in the first method. In the second method the value of N is not known at compile time, and as such there is no way for the compiler to know how much space to allocate for a. Hope that helps.

puzzlepalace
  • 660
  • 5
  • 13
1

This sort of thing is an implementation detail that technically is up to the compiler to choose. It could be different on different platforms.

In practice, with the most common compilers:

const int sometimes is and sometimes isn't baked at compile time. For example, the compiler clearly can't hardcode the value of a below into the object file:

int foo( int x ) 
{
  const int a = x+ 1; 
  return a * 2;
}

In that function, const means it is only constant within the scope of foo(), but it is still a local stack variable.

On the other hand, const int x = 5 seems to be a literal that is usually resolved at compile time by GCC and MSVC (except sometimes they don't turn it into a literal for reasons unclear). I've seen some other compilers that won't turn it into a literal, and always put const int on the stack like an ordinary local variable.

const static int is different, because its scope is static, which means it outlives the function it is declared in, which means it will never change over the life of the program. Every compiler I've ever worked with has turned const static primitives into compile-time literals.

Objects with constructors, however, will still need to be initialized at runtime; so

class Foo { 
    Foo() : { CallGlobalFunction(); }  
}; 
const static Foo g_whatever;

cannot be optimized into a literal by the compiler.

Crashworks
  • 40,496
  • 12
  • 101
  • 170
  • There should be no difference with regards to compilers. The standard says quite clearly when an expression is a "constant integral expression", and when it isn't. – James Kanze Nov 20 '14 at 19:59
  • @JamesKanze I'm just saying what I've observed by looking at the emitted assembly. – Crashworks Nov 20 '14 at 20:00
  • And what I'm saying is based on the specifications of the language. The compilers are required to treat some things as compile time constants, and forbidden to treat others as such, regardless of what they can do in the optimizer. – James Kanze Nov 20 '14 at 20:01
  • @JamesKanze Sure, but I'm answering the specific question of whether `const int x = 5` is evaluated at compile time. A semantic requirement that `const int` can be used like a literal in eg initializing arrays doesn't necessarily mean that compiler actually turns it into a literal. Regrettably, our C++ code is turned into executable machine instructions by a compiler program, and not by a standards document. I've seen code generation that departs from the letter of the standard many times. – Crashworks Nov 20 '14 at 20:06
  • Do you mean that the first example wouldn't be supported by all the compilers? – andy90 Nov 20 '14 at 20:23
  • 1
    @andy90 No, the use of a const integral to define an array size should work in all compilers. But the precise question "whether sentences like const int N=10 will be executed at compilation time" is slippery -- some compilers will generate code as if you had typed `10` instead of `N` everywhere in the function; others will actually make a variable `N` on the stack, store 10 in it, and then use it like an ordinary local. – Crashworks Nov 20 '14 at 21:14
  • 1
    @Crashworks And some compilers will do both. If you pass `N` to a function which takes a reference, or `&N` to a function which takes a pointer, the compiler is pretty much forced to generate an instance of `N` on the stack (unless the function is inlined). And when you declare an array with a dimension of `N`, the compiler is required to treat `N` as a constant expression, and use its value directly in the compiler. – James Kanze Nov 21 '14 at 10:35