how do static variables inside functions work?

后端 未结 3 2228
花落未央
花落未央 2021-02-19 04:20

In the following code:

int count(){
    static int n(5);
    n = n + 1;
    return n;
}

the variable n is instantiated only once a

3条回答
  •  萌比男神i
    2021-02-19 05:05

    This is, of course, compiler-specific.

    The reason you didn't see any checks in the generated assembly is that, since n is an int variable, g++ simply treats it as a global variable pre-initialized to 5.

    Let's see what happens if we do the same with a std::string:

    #include 
    
    void count() {
        static std::string str;
        str += ' ';
    }
    

    The generated assembly goes like this:

    _Z5countv:
    .LFB544:
            .cfi_startproc
            .cfi_personality 0x3,__gxx_personality_v0
            .cfi_lsda 0x3,.LLSDA544
            pushq   %rbp
            .cfi_def_cfa_offset 16
            movq    %rsp, %rbp
            .cfi_offset 6, -16
            .cfi_def_cfa_register 6
            pushq   %r13
            pushq   %r12
            pushq   %rbx
            subq    $8, %rsp
            movl    $_ZGVZ5countvE3str, %eax
            movzbl  (%rax), %eax
            testb   %al, %al
            jne     .L2                     ; <======= bypass initialization
            .cfi_offset 3, -40
            .cfi_offset 12, -32
            .cfi_offset 13, -24
            movl    $_ZGVZ5countvE3str, %edi
            call    __cxa_guard_acquire     ; acquire the lock
            testl   %eax, %eax
            setne   %al
            testb   %al, %al
            je      .L2                     ; check again
            movl    $0, %ebx
            movl    $_ZZ5countvE3str, %edi
    .LEHB0:
            call    _ZNSsC1Ev               ; call the constructor
    .LEHE0:
            movl    $_ZGVZ5countvE3str, %edi
            call    __cxa_guard_release     ; release the lock
            movl    $_ZNSsD1Ev, %eax
            movl    $__dso_handle, %edx
            movl    $_ZZ5countvE3str, %esi
            movq    %rax, %rdi
            call    __cxa_atexit            ; schedule the destructor to be called at exit
            jmp     .L2
    .L7:
    .L3:
            movl    %edx, %r12d
            movq    %rax, %r13
            testb   %bl, %bl
            jne     .L5
    .L4:
            movl    $_ZGVZ5countvE3str, %edi
            call    __cxa_guard_abort
    .L5:
            movq    %r13, %rax
            movslq  %r12d,%rdx
            movq    %rax, %rdi
    .LEHB1:
            call    _Unwind_Resume
    .L2:
            movl    $32, %esi
            movl    $_ZZ5countvE3str, %edi
            call    _ZNSspLEc
    .LEHE1:
            addq    $8, %rsp
            popq    %rbx
            popq    %r12
            popq    %r13
            leave
            ret
            .cfi_endproc
    

    The line I've marked with the bypass initialization comment is the conditional jump instruction that skips the construction if the variable already points to a valid object.

提交回复
热议问题