标准里说对于 function 里面 static 变量只说了两点:
Variables declared at block scope with the specifier static have static storage duration but are initialized the first time control passes through their declaration (unless their initialization is zero- or constant-initialization, which can be performed before the block is first entered). On all further calls, the declaration is skipped.
https://en.cppreference.com/w/cpp/language/storage_duration
比如
int f()
{
static int a = 0;
}
int main()
{
f();
std::cout << "---------------" << std::endl;
f();
return 0;
}
1
zycpp 2019-06-04 17:31:54 +08:00 via iPhone
#include <iostream>
class A{ public: A(){printf("create\n");} ~A(){printf("destroy\n");} }; void f(){ static A a; } int main(){ printf("before call f\n"); f(); printf("after call f\n"); f(); printf("the end\n"); return 0; } |
2
wutiantong 2019-06-04 17:45:04 +08:00 via iPhone
问题 1,如果你没运行到 f,a 是不存在的(未分配内存),更不必讨论初始化。这点你在引文里其实已经提到了。
编译器如何实现的我也不清楚,但一定不是你说的这样 |
3
Akiyu 2019-06-04 17:57:49 +08:00
你分析汇编就知道了
static 具有线程安全性, 因为访问的时候会加锁 我记得我写过笔记, 我找找啊 = = |
4
yianing 2019-06-04 18:10:18 +08:00 via Android
static 变量在程序装载到内存时就会被初始化,有初值的赋初值,没有的是 0,程序员的自我修养书上有
|
5
Akiyu 2019-06-04 18:19:58 +08:00
找不到了, 直接分析一下吧 = =
原始代码 : void func(int a) { static int i = a; cout << i << endl; i++; } 汇编代码: -- 这是调用的: movl▹ $100, %edi call▹ _Z4funci -- 这是 func 函数的: _Z4funci: .LFB3222: ▹ pushq▹ %rbp ▹ movq▹ %rsp, %rbp ▹ subq▹ $16, %rsp ▹ movl▹ %edi, -4(%rbp) // 参数入栈 ▹ movl▹ $_ZGVZ4funciE1i, %eax ▹ movzbl▹ (%rax), %eax // 这里就是某个标志位, 标识了静态变量是否被初始化了, 当翻译成机器码时, 这是一个绝对地址 ▹ testb▹ %al, %al // 检测某个位 ▹ jne▹.L2 ▹ movl▹ $_ZGVZ4funciE1i, %edi ▹ call▹ __cxa_guard_acquire // 关键字 guard_acquire, 获取锁 ▹ testl▹ %eax, %eax ▹ setne▹ %al ▹ testb▹ %al, %al ▹ je▹ .L2 ▹ movl▹ -4(%rbp), %eax // 参数放入寄存器 eax ▹ movl▹ %eax, _ZZ4funciE1i(%rip) // 经过前面的检测后, 这里才会设置值 ▹ movl▹ $_ZGVZ4funciE1i, %edi ▹ call▹ __cxa_guard_release // 关键字 guard_release, 释放锁 .L2: ▹ movl▹ _ZZ4funciE1i(%rip), %eax // 这里是直接使用的, 前面的 jne 会跳转到这里 ▹ movl▹ %eax, %esi ▹ movl▹ $_ZSt4cout, %edi ▹ call▹ _ZNSolsEi ▹ movl▹ $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, %esi ▹ movq▹ %rax, %rdi ▹ call▹ _ZNSolsEPFRSoS_E ▹ movl▹ _ZZ4funciE1i(%rip), %eax ▹ addl▹ $1, %eax ▹ movl▹ %eax, _ZZ4funciE1i(%rip) ▹ leave ▹ ret 简单来说, 内存中有一个绝对地址(由编译器提供并维护)的某个位, 它标志了静态变量是否被初始化 然后如果未初始化, 先会获得锁, 初始化, 设置完后再释放锁 |
6
Akiyu 2019-06-04 18:20:54 +08:00
当然, 这视编译器而异
有些的实现是直接初始化了 |
7
sky2017 2019-06-04 19:11:33 +08:00
局部 static 变量是第一次执行到的时候才初始化,并且存在线程安全问题
|
10
zzjas98 2019-06-05 01:37:04 +08:00
Q1: static 的东西会被存到 bss 去,看下这里可能有帮助 https://en.wikipedia.org/wiki/.bss
TL;DR “ On some platforms, some or all of the bss section is initialized to zeroes. Unix-like systems and Windows initialize the bss section to zero, allowing C and C++ statically-allocated variables initialized to values represented with all bits zero to be put in the bss segment.” Q2: static int a = 0 这一句第一次执行之后,以后再遇到会被跳过。具体怎么实现不知道,可能因编译器而异吧 借用 5 楼的例子多写了一些: https://imgur.com/RNdB7vL https://imgur.com/3ZRnxxN |
11
zzjas98 2019-06-05 01:56:06 +08:00
啊不对才注意到到楼主的例子是 static int a = 0,我 Q1 说的是针对“ static int a;”的。还真没找到 function scoped,initialized,static variable 被 initialize 之前的值是什么。。。但是它肯定会在第一次 function invocation 时候被 intialize,以后执行会直接跳过那句。
这个链接或许有帮助: https://web.archive.org/web/20100328062506/http://www.acm.org/crossroads/xrds2-4/ovp.html 另外,这个或者 1 楼的回复可以测试那个 declaration 被执行了几次 #include <iostream> using namespace std; void func(int a) { static int i = (printf("declaration\n")) ? a:a; cout << i << endl; i++; } int main() { func(5); func(10); } |