Search code examples
cinternals

When initializing variables in C does the compiler store the intial value in the executable


When Initializing variables in C I was wondering does the compiler make it so that when the code is loaded at run time the value is already set OR does it have to make an explicit assembly call to set it to an initial value?

The first one would be slightly more efficient because you're not making a second CPU call just to set the value.

e.g.

void foo() {
  int c = 1234;
}

Solution

  • If it's a variable with static lifetime, it'll typically become part of the executable's static image, which'll get memcpy'ed, along with other statically known data, into the process's allocated memory when the process is started/loaded.

    void take_ptr(int*);
    
    void static_lifetime_var(void)
    {
        static int c = 1234;
        take_ptr(&c);
    }
    

    x86-64 assembly from gcc -Os:

    static_lifetime_var:
            mov     edi, OFFSET FLAT:c.1910
            jmp     take_ptr
    c.1910:
            .long   1234
    

    If it's unused, it'll typically vanish:

    void unused(void)
    {
        int c = 1234;
    }
    

    x86-64 assembly from gcc -Os:

    unused:
            ret
    

    If it is used, it may not be necessary to put it into the function's frame (its local variables on the stack)—it might be possible to directly embed it into an assembly instruction, or "use it as an immediate":

    void take_int(int);
    
    void used_as_an_immediate(int d) 
    {
      int c = 1234;
      take_int(c*d);
    }
    

    x86-64 assembly from gcc -Os:

    used_as_an_immediate:
            imul    edi, edi, 1234
            jmp     take_int
    

    If it is used as a true local, it'll need to be loaded into stack-allocated space:

    void take_ptr(int*);
    
    void used(int d)
    {
      int  c = 1234;
      take_ptr(&c);
    }
    

    x86-64 assembly from gcc -Os:

    used:
            sub     rsp, 24
            lea     rdi, [rsp+12]
            mov     DWORD PTR [rsp+12], 1234
            call    take_ptr
            add     rsp, 24
            ret
    

    When pondering these things Compiler Explorer along with some basic knowledge of assembly are your friends.