Is variable defined by const int determined at compilation time? - c++

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;
}

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.

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.

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.

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.

Related

Branch with if constexpr() on constinit variables? [duplicate]

I ran across this seemingly odd behavior. A const at top level can be used for array size declarations, but not when the const is in a class.
Here's a compiler explorer demo for MSVC, CLANG and GCC all producing an error:
expression did not evaluate to a constant
It's not really a constant if it's not const at the top level?
There's some argument to be made because top level constants can often be stored in read-only memory, while constants that are not at top level cannot. But is this behavior correct?
struct A {
const int i{ 3 };
};
int main()
{
const int ii{ 3 };
A a;
int j[a.i]{}; // C2131: expression did not evaluate to a constant
int k[ii]{};
}
Generally, you can use (meaning perform an lvalue-to-rvalue conversion on) objects with lifetime starting outside a constant expression only if they are variables marked constexpr or their subobjects (plus some other special cases, that I don't think are important here, see [expr.const]/4 for details).
That you can use a const int variable at all in a constant expression is already a very specific exception. Essentially const-qualified integral and enumeration type variables are also usable in constant expressions if you could have added constexpr to them (meaning that their initializer expression is a constant expression).
This exception is there I guess purely for historical reasons, since it had been allowed before constexpr was introduced in C++11.
Note that all of this talks about variables and their subobjects. Non-static data members are specifically not variables and the exception doesn't apply to them. With constexpr this is more obvious by not allowing it on the declaration of a non-static data member in the first place.
The historical rule was never extended to encompass other types that could be marked constexpr, so e.g. const A a; will not help although that would actually cause a to be storable in read-only memory the same way a const int would.
If an object is none of the cases mentioned above, then an lvalue-to-rvalue conversion on it in a constant expression is not allowed, since it is assumed that the value of the object is not determined at compile-time.
Now, in theory the compiler could still do some constant folding and determine that even other objects' values are definitively known at compile-time. But I think the intention is that whether or not an expression is a constant expression should be (reasonably) well-defined independently of the implementation and so shouldn't rely on how much analysis the compiler can do.
For example
A a;
A b(a);
is also guaranteed to result in b.i == 3. How far do you want to require a compiler to go back or keep track of evaluations? You would need to make some definitive specification if you want to keep the behavior consistent between compilers. But there is already a simple method to indicate that you want the compiler to keep track of the values. You just have to add constexpr:
constexpr A a;
constexpr A b(a);
Now b.i can be used as array index (whether or not it is const and whether or not it is initialized).
With the current rules, any compiler only needs to evaluate the value of objects at compile-time when it sees a constexpr variable or a const integral/enumeration type variable. For all other variables it doesn't need to keep track of values or backtrack when it sees them used in a context which requires a constant expression.
The additional effect of constexpr implying const on the variable makes sure that its value will also never be changed in a valid program and so the compiler doesn't need worry about updating or invalidating the value after the initial computation either. And whether or not an expression is a constant expression is (mostly) implementation-dependent.
ii is a compile-time constant. Its value is known at compile-time, and cannot be changed at runtime. So, ii can be used for fixed array sizes at compile-time.
A::i is not a compile-time constant. It is a non-static instance member. Its value is not known until runtime. After an A object is constructed and its i member is initialized, the value of i cannot be changed because of the const, but the caller can initialize i with whatever value it wants, eg: A a{123};, and thus different A objects can have different i values. So, i cannot be used for fixed array sizes at compile-time. But, it can be used for dynamic array sizes at runtime, via new[], std::vector, etc.
TL;DR
Your assumption that const always implies compile time constant is incorrect. See examples at the end of this answer for more details on this.
Now the problem in using a.i as the size of an array is that in standard C++, the size of an array must be a compile time constant, but since i is a non-static data member, it requires an object to be used on. In other words, after construction of the class object nonstatic data member i gets initialized, which in turn means that a.i is not a constant expression, hence we get the mentioned error saying:
expression did not evaluate to a constant
To solve this, you can make i be a constexpr static data member, as shown below. This works because using a static data member doesn't require an object instance (and hence no this pointer).
struct A {
constexpr static int i{ 3 };
};
int main()
{
const int ii{ 3 };
A a;
int j[a.i]{}; //Correct now and works in all compilers
int k[ii]{};
}
I just don't get why a regular const works in some places but not others.
Perhaps you assuming that const implies compile time constant which is a wrong assumption. An example might help you understand this better:
int i = 10; //i is not a constant expression
const int size = i; //size is not a constant expression as the initializer is not a constant expression
//------vvvv------>error here as expected since size is not a constant expression
int arr[size]{};
On the other hand if you were to make i const as shown below, the program will work fine.
const int i = 10; //note the const added here so that now i is a constant expression
const int size = i; //size is a constant expression as the initializer is a constant expression
//------vvvv------>NO ERROR HERE as expected since size is a constant expression
int arr[size]{};

Should I avoid static constexpr local variables? If so, why?

Consider code like the following, where the literal some_magic_int (e.g. 3) is given a name just to make a bit clearer what constant it represents:
void f() {
static constexpr int this_variable{some_magic_int};
do_something_with(this_variable);
}
int main() {
// ...
f();
// ...
}
I'm pretty sure constexpr has to be here: some_magic_int is literal, so it never changes, and I'm giving it a name just for clarity, not to give a mean to change it, so it should be at least const; then why not constexpr to have it at compile-time?
But what about static? Is it just unnecessary? Or is it detrimental? If so, why? And also, does it have any observable effect, when paired with constexpr in the declaration of a local variable?
As regards the question to which this is marked as duplicate of, it is about static constexpr int x [] = {}, and not static constexpr int x {}. This highlights at least one difference between that case (attributes applying to x pointer vs attributes applied to *x pointee) and my case (there's no pointer).
Furthermore, once I add constexpr to the specifier of a local variable (where it makes sense, e.g. to a int), I'm saying that variable is compile-time known. Why in the world doesn't that imply that no run-time entity is needed whatsoever?
The standard doesn’t actually ever talk about compile-time anything except to say that types are checked and templates are instantiated before execution. That means that this program must be diagnosed (not “rejected”!) even though the non-constant array length and template argument are never “used” and might plausibly be ignored by an interpreter:
template<int> void f() {}
int main(int argc,char **argv) {
if(false) {
int buf[argc]; // accepted by a common extension
f<argc>();
}
}
Beyond that, the semantics are that every evaluation is part of the ordinary execution of the program and constant folding is just an as-if optimization like any other. (After all, we can optimize argc*2*3*4 even though it contains no non-literal subexpression that could be a constant expression.) For constant expressions, this is largely unobservable because constant evaluation can’t have side effects (which also avoids interactions among constant-initialized non-block variables). It can, however, make a difference via the address of the local variable:
bool introspect(const int *p=nullptr) {
constexpr int x=0;
return p ? p==&x : introspect(&x); // always false
}
That the compiler must make such variables occupy memory if their address escapes is much of the content of the answers to the previously marked duplicate. It therefore makes sense to prefer static except perhaps when the object is large and its address doesn’t matter (e.g., for use as a template argument or via recursion).

Const Int declared with stoi not considered a const

I wrote a simple test program using CGAL, and running into the following issue:
Point is defined above as
typedef K::Point_d Point;
but I don't think this is relevant.
When I attempt to compile the program as follows:
const int size = 10;
Point P[size];
g++ does so without issue.
If instead I attempt to compile:
const int size = stoi("10");
Point P[size]
I get the following error
error: variable length array of non-POD element type 'Point' (aka 'Point_d<Cartesian_d<double,
CGAL::Linear_algebraCd<double, std::__1::allocator<double> > > >')
Why is size considered a variable instead of a const when retrieved from a string?
C++ defines specific things to be constant expressions that are defined to be known at compile time - see constant_expression.
In general functions that are not defined as constexpr are not, regardless of what you pass them. You could try and force it as such:
#include<string>
constexpr int x = std::stoi("10");
int main() {
return 0;
}
but you will find this still leads to an error:
error: call to non-constexpr function 'int std::stoi(const string&, std::size_t*, int)'
so, you are out of luck as stoi is not a constant expression. If you really insist you could override this using your own implementation for example that in How do I convert a C string to a int at compile time?.
stoi is not evaluated at compile time. That means the compiler does not know how big the array should be.
if you want to do something like that you have to use a constexpr function (constexpr function). These can be evaluated at compile time, then it works.
The compiler doesn't understand the semantics of the stoi function. All it sees is you calling a function that returns an integer (whether that function can be inlined and optimized away is a seperate issue from the semantics).
To the compiler there is very little semantic difference between
const int size = stoi("10");
and
const int size = getchar();
As other answers mentioned constexpr being the exception. I just thought I'd illustrate the issue.
The first const int size = 10; is a compile time const expression and it can be computed during compilation,
but const int size = stoi("10") is not a compile time const expression hence it fails to compile.
std::stoi is not a constexpr function to evaluated on compile time.
If you want to have this functionality you may need to create a constexpr function to evaluate on compile time.
constexpr bool is_digit(char c) {
return c <= '9' && c >= '0';
}
constexpr int stoi_impl(const char* str, int value = 0) {
return *str ?
is_digit(*str) ?
stoi_impl(str + 1, (*str - '0') + value * 10)
: throw "compile-time-error: not a digit"
: value;
}
constexpr int to_int(const char* str) {
return stoi_impl(str);
}
int main() {
constexpr int size = to_int("10");
int arr[size];
}
This will compile; [copied from here]
In the first code sample
const int size = 10;
Point P[size];
the particular value of size can be used already at compile time, since it is known (you've specified it). Therefore the compiler may replace all its uses with particular value, w/o actually creating a variable.
In the second sample
const int size = stoi("10");
Point P[size]
the compiler cannot know the value, since it is deduced by the stoi function at runtime. Therefore it cannot substitute the size of the array (which must be known beforehand to determine now much memory to allocate), and you get the error.
In C++11 there is constexpr idiom, which allows some functions, declared as constexpr, be evaluated at compile time. But in your case stoi isn't constexpr function, so you cannot achieve what you want using this particular function. You can implement your own constexpr stoi, but I don't see much sence in it, since your code in this case would contain somethins like this: my_constexpr_stoi("10"), i.e. the argument is always manually written and always known beforehand. Why don't write just 10?..
To expand on kabanus’ answer, the language standard says that an array bound in C++11 must be something called an integral constant expression. C++17 relaxes this slightly and allows a few more things, but that’s not important right now.
This page at cppreference lists all the things you are not allowed to do inside a constant expression. It basically quotes the language standard.
The relevant section that allows your first example is 8a. You are not allowed to use a variable, unless it’s a const variable initialized to a constant expression. So using the name of a const variable of integral type that is initialized to a constant expression is legal, as in your first example. Numeric constants are constant expressions, so size is a const variable initialized to a constant expression, which is A-OK.
However, due to point 2, function calls are only constant expressions if they are both declared constexpr and already defined. So, for a standard library function to be usable in an array expression in your code, it would need to be declared constexpr and also defined in the header file.
The standard does not say that stoi() qualifies, although I don’t think anything in it directly forbids some implementation from providing that as an extension.

static variable initialization in C

I was disappointed to learn recently that C does not allow assignment of variables during static variable initialization, unlike C++. E.g. the following code compiles as C++...
#include <stdio.h>
int foo()
{
return 1;
}
static int g_i = foo();
int main( int argc, char* argv[] )
{
printf( "%d\n", g_i );
return 0;
}
...but issues the following error with a C compiler:
>cc -g main.c
main.c:8:1: error: initializer element is not constant
static int g_i = foo();
^
I thought I could be clever by using the comma operator a-la:
static int g_i = ( foo(), 1 );
...but the compiler seemed unimpressed with my attempted cleverness, and output effectively the same error:
>cc -c main.c
main.c:8:1: error: initializer element is not constant
static int g_i = ( foo(), 1 );
^
:(
Q: Why does use of the comma operator not work? I may be unaware of some subtlety, but my understanding led me to think it should have worked: the C compiler is demanding g_i be initialzed to a compiletime constant; supposedly the comma operator would have offered me evaluation of the code left of the comma, but assignment of the code right of the comma, which is a compiletime constant.
Q: Are there any hacks - I don't care how dirty - that would allow assignment to g_i the return value of foo() to g_i?
This is a simplified representation of a C program where I really just want to call a function before main() - I don't care about the return value, but it's a more complicated problem to call a void function before main(), which I would rather sidestep altogether by using an int function whose value is assigned to a throwaway static int variable.
C does not support dynamic initialization. For this reason, static objects are required to be initialized with constant expressions. Constant expressions are not allowed to involve any run-time computations, even if these computations do not affect the final value of the expression. Your expression with comma operator is not a constant expression.
(Moreover, comma operator is prohibited in C constant expressions even if you don't call any functions from them. E.g. even something as trivial as (1, 2, 3) is not a constant expression either.)
All static objects in C have to be initialized at compile time, at least conceptually. The word "conceptually" in this case refers to the fact that, say, address constant expressions may actually be evaluated much later, even at load time. But the point is that once your program starts running any user-level code, all static objects have to have already known pre-evaluated values, as if they were initialized at compile time. For this reason C (as opposed to C++) does not have/does not need the concept of initialization order for static objects and cannot possibly suffer from SIOF.
So, there's no way around this restriction in standard C. You will not be able to initialize a static object with something that requires (or in any way involves) running code at run-time. Your implementation might provide implementation-specific features that might be able to do something like that, but this is way outside the realm of C language itself.

constexpr vs const: Will use a constexpr instead of const better help compile to optmize?

Will use a constexpr instead of const better help compile to optmize? I have some value that are constant. I could use an enum instead of but they aren't all of same type and I don't want to use #defines for ovious reasons. They are declared like below code. My question is: if I use constexpr will it increase possibilities to compiler replace the value where it's used by the literal constant value or it doesn't differ if I use const? I know it's up to each compiler if does or doesn't the optmization but a "general" answer as it behave in most compiler is very welcome. Also, assuming the result are different for simple locals like this it's different too if instead of they are member of a struct/class? is const folding most hard to be performed in this cases?
e.g,
int foo()
{
constexpr int x = 10;
constexpr int y = x * 3;
do_domsething(y + n);
}
versus
int foo()
{
const int x = 10;
const int y = x * 3;
do_domsething(y + n);
}
Today, constexpr is still pretty new and might fall through some optimization cracks. Calculation of the variable's own value is required to be performed at compile time, of course. In the long run, I'd expect the same optimization opportunities for each. Obviously when that happens is compiler-specific.
Just use whichever one has clearer meaning to you and anyone else working on the code, not only in terms of behavior but also intent.
Among other things, note that constexpr guarantees the constant has the same value always, whereas const allows it to have a different value each time initialization is reached (it can't be changed except by initialization, of course). But nearly every compiler on the planet will determine that for your example, the values really are constant.
One more thing: constexpr compile-time evaluation (like template argument calculation) is active even when optimizations are disabled.