C++ static 关键字

2019-06-04 16:55:24 +08:00
 hackpro

标准里说对于 function 里面 static 变量只说了两点:

  1. 分配在静态存储区
  2. 第一次遇到的时候进行初始化,之后每次跳过。

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. 程序起来,静态存储区创建 int a; 此时并未运行到 f(),这时静态存储区的值 a 是否 undefined?还是说类似全局变量初始化,数值类型给 0 值,字符串给空?
  2. 第一次进入 f()运行到 static int a = 0 时,静态存储区的 a 被初始化为 0 ?之后每次进入 f()这个语句直接被忽略掉?编译器是如何实现的?类似于一个 loop ?初始值 cnt=1,用完 cnt--,下次 check 值是否为 0 进行跳转?
2986 次点击
所在节点    C
11 条回复
zycpp
2019-06-04 17:31:54 +08:00
#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;
}
wutiantong
2019-06-04 17:45:04 +08:00
问题 1,如果你没运行到 f,a 是不存在的(未分配内存),更不必讨论初始化。这点你在引文里其实已经提到了。

编译器如何实现的我也不清楚,但一定不是你说的这样
Akiyu
2019-06-04 17:57:49 +08:00
你分析汇编就知道了
static 具有线程安全性, 因为访问的时候会加锁
我记得我写过笔记, 我找找啊 = =
yianing
2019-06-04 18:10:18 +08:00
static 变量在程序装载到内存时就会被初始化,有初值的赋初值,没有的是 0,程序员的自我修养书上有
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

简单来说, 内存中有一个绝对地址(由编译器提供并维护)的某个位, 它标志了静态变量是否被初始化
然后如果未初始化, 先会获得锁, 初始化, 设置完后再释放锁
Akiyu
2019-06-04 18:20:54 +08:00
当然, 这视编译器而异
有些的实现是直接初始化了
sky2017
2019-06-04 19:11:33 +08:00
局部 static 变量是第一次执行到的时候才初始化,并且存在线程安全问题
zmj1316
2019-06-04 19:20:52 +08:00
@Akiyu 好像是 c++ 11 开始才是线程安全的
Akiyu
2019-06-04 19:33:44 +08:00
@zmj1316
这个我就不太清楚了, 我直接学的 C++ 11
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
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);
}

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/570815

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX