casyup.me@outlook.com

0%

read/static_filed_in_Cpp

@brief

when I learning java by , I see “The order of initialization is statics first…”. so… what about c++?

当我通过 thinking in java 学 java 时, 我注意到书中的一句话 “The order of initialization is statics first”. 那么, c++ 中是怎样对待的呢?

static

think this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class A{
public:
int i2 = 1;
static int i;
A() { cout << "hello" << endl; }
};

int A::i = 10;

void f() {
A a;
cout << A::i << endl;
A::i = 100;
}

int main() {
A a;
cout << A::i << endl;
thread t1(f);
thread t2(f);
t1.join();
t2.join();
}

class A has a static field i, it’s an integer with default value 10.

how did these codes do?

类 A 有一个静态字段 i, 这是一个具有默认值为10的整型字段

assembly time

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
_ZN1A1iE:
▹ .long▹ 10
▹ .text
▹ .globl▹ _Z1fv
▹ .type▹ _Z1fv, @function
_Z1fv:
.LFB3324:
▹ .cfi_startproc
▹ pushq▹ %rbp
▹ .cfi_def_cfa_offset 16
▹ .cfi_offset 6, -16
▹ movq▹ %rsp, %rbp
▹ .cfi_def_cfa_register 6
▹ subq▹ $16, %rsp
▹ leaq▹ -4(%rbp), %rax
▹ movq▹ %rax, %rdi
▹ call▹ _ZN1AC1Ev
▹ movl▹ _ZN1A1iE(%rip), %eax // _ZN1A1iE
▹ movl▹ %eax, %esi
▹ leaq▹ _ZSt4cout(%rip), %rdi
▹ call▹ _ZNSolsEi@PLT
▹ movq▹ %rax, %rdx
▹ movq▹ _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GOTPCREL(%rip), %rax
▹ movq▹ %rax, %rsi
▹ movq▹ %rdx, %rdi
▹ call▹ _ZNSolsEPFRSoS_E@PLT
▹ movl▹ $100, _ZN1A1iE(%rip)
▹ nop
▹ leave
▹ .cfi_def_cfa 7, 8
▹ ret
...
main:
.LFB3325:
▹ .cfi_startproc
▹ .cfi_personality 0x9b,DW.ref.__gxx_personality_v0
▹ .cfi_lsda 0x1b,.LLSDA3325
▹ pushq▹ %rbp
▹ .cfi_def_cfa_offset 16
▹ .cfi_offset 6, -16
▹ movq▹ %rsp, %rbp
▹ .cfi_def_cfa_register 6
▹ pushq▹ %rbx
▹ subq▹ $40, %rsp
▹ .cfi_offset 3, -24
▹ leaq▹ -20(%rbp), %rax
▹ movq▹ %rax, %rdi
.LEHB0:
▹ call▹ _ZN1AC1Ev
▹ movl▹ _ZN1A1iE(%rip), %eax // _ZN1A1iE
▹ movl▹ %eax, %esi
▹ leaq▹ _ZSt4cout(%rip), %rdi
▹ call▹ _ZNSolsEi@PLT
▹ movq▹ %rax, %rdx
▹ movq▹ _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GOTPCREL(%rip), %rax
▹ movq▹ %rax, %rsi
▹ movq▹ %rdx, %rdi
▹ call▹ _ZNSolsEPFRSoS_E@PLT
▹ leaq▹ -32(%rbp), %rax
▹ leaq▹ _Z1fv(%rip), %rsi
▹ movq▹ %rax, %rdi
▹ call▹ _ZNSt6threadC1IRFvvEJEEEOT_DpOT0_

so, static value initialize while process run then copy to register while class construct function executed

所以, 静态变量随着程序运行而初始化, 随后在类构造函数完成后, 将其值拷贝到寄存器

this can also be discovered in gdb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(gdb) b main
Breakpoint 1 at 0x1908: file t.cpp, line 33.
(gdb) c
The program is not being run.
(gdb) r
Starting program: /root/cpp/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main () at t.cpp:33
33 A a;
(gdb) p A::i
$2 = 10
(gdb) p &A::i
$3 = (int *) 0x555555758100 <A::i>
(gdb) p (int)0x555555758100
$4 = 1433764096
(gdb) p {int}0x555555758100
$5 = 10

how about static const?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class A{
public:
int i2 = 1;
static int const i = 11;
A() { cout << "hello" << endl; }
};
...
_Z1fv:
.LFB3324:
▹ .cfi_startproc
▹ pushq▹ %rbp
▹ .cfi_def_cfa_offset 16
▹ .cfi_offset 6, -16
▹ movq▹ %rsp, %rbp
▹ .cfi_def_cfa_register 6
▹ subq▹ $16, %rsp
▹ leaq▹ -4(%rbp), %rax
▹ movq▹ %rax, %rdi
▹ call▹ _ZN1AC1Ev
▹ movl▹ $11, %esi // *
▹ leaq▹ _ZSt4cout(%rip), %rdi
...
main:
.LFB3325:
▹ .cfi_startproc
▹ .cfi_personality 0x9b,DW.ref.__gxx_personality_v0
▹ .cfi_lsda 0x1b,.LLSDA3325
▹ pushq▹ %rbp
▹ .cfi_def_cfa_offset 16
▹ .cfi_offset 6, -16
▹ movq▹ %rsp, %rbp
▹ .cfi_def_cfa_register 6
▹ pushq▹ %rbx
▹ subq▹ $40, %rsp
▹ .cfi_offset 3, -24
▹ leaq▹ -20(%rbp), %rax
▹ movq▹ %rax, %rdi
.LEHB0:
▹ call▹ _ZN1AC1Ev
▹ movl▹ $11, %esi // *
▹ leaq▹ _ZSt4cout(%rip), %rdi

if you use static const, there no space to store value, just a compile-time const value

如果使用static const, 则不会有空间存储值, 则是一个编译时常量