Home > Back-end >  Why it takes me a long time to compile this simple C code
Why it takes me a long time to compile this simple C code

Time:07-17

When I try to compile C code like this, it takes me 71s:

#include<bits/stdc  .h>
struct S{int v=1;}a[1<<25];
int main(){
    return 0;
}

However, when I change the 1 to 0, it compiles in just 1s:

#include<bits/stdc  .h>
struct S{int v=0;}a[1<<25];
int main(){
    return 0;
}

I know I can use something like S(){v=1;}, but I just want to know about this interesting difference.

System:   MacOS 12.4
Compiler: g  -11 (Homebrew GCC 11.3.0_2) 11.3.0

CodePudding user response:

In your original case with struct S{int v=1;}a[1<<25];, a's initialization is a constant expression. Therefore the compiler needs to evaluate the value of the whole array at compile-time and store the result in the executable. (Generally in the .data segment.) The constant evaluation and keeping track of the stored value probably takes some significant overhead for the compiler. (Someone with knowledge of the GCC internals may be able to give more details on that.)

If you add a constructor of the form S(){v=1;}, then because this constructor is not constexpr and will be chosen to construct the array elements, a will not be constant-initialized. Instead of evaluating and storing the array value, the compiler will just add instructions to the executable asking the program loader to allocate (and zero-initialize) memory for the array when the program is executed (generally via the .bss segment) and will then properly initialize the array before entering main at runtime.

If you use int v=0; instead of int v=1;, then you still have constant-initialization, but the value of the whole array will be zero. This means again that the compiler only needs to add instructions for memory to be allocated for the array when the program starts. Such memory is automatically zero-initialized before execution of the program starts, so no further runtime initialization is required, keeping in line with the constant-initialization requirements. The compiler seems to be clever enough to recognize that here and seems to also optimize the evaluation/storage of the constant expression evaluation for this common case.

At some point if the array is large enough, the initialization will again become non-constant-initialization and therefore potentialy compile more quickly, because there is an implementation-defined limit on the number of operations in a constant expression. If this limit is exceeded the initialization is no longer a constant expression and initialization of the array will happen at runtime again. Still, the compiler probably has to evaluate that many operations first before noticing that the limit is exceeded, which may also take significant compilation time. Compilers typically have configuration options for that limit, e.g. for GCC -fconstexpr-ops-limit and others, although I couldn't manage to get them to compile here faster. MSVC and Clang do actually seem to apply the limit (in the default configuration) and compile your initial example quickly as well.

  • Related