初始化静态变量只能是固定表达式 实际我验证用变量初始化也可以

量化分析 2014-08-29 05:39:19
int y=20;
static int k1=y*20;

cout<<"k1 "<<k1<<endl;

居然可以输出400,求解
按照常理,静态变量在程序运行前已经开辟了空间,并存了值。初始化的时候y的值还不知道呢
...全文
281 14 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
fefe82 2015-11-22
  • 打赏
  • 举报
回复
c++14 draft n4296 6.7 Declaration statement 4 The zero-initialization (8.5) of all block-scope variables with static storage duration (3.7.1) or thread storage duration (3.7.2) is performed before any other initialization takes place. Constant initialization (3.6.2) of a block-scope entity with static storage duration, if applicable, is performed before its block is first entered. An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope (3.6.2). Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.92 If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined. 局部静态变量的初始化可以发生在程序运行第一次经过变量定义的时候。 可以使用常量或者表达式等。
量化分析 2015-11-22
  • 打赏
  • 举报
回复
引用 11 楼 lovesmiles 的回复:
既然是变量,自然是可以变的。 又不是常量。
我是说可以改变,只是纠结于static应该先于y就开辟空间了。现在大概也懂了。 即使刚开始k的值不明,后来y有了值之后,就重新修改了k的值。
derekrose 2014-08-31
  • 打赏
  • 举报
回复
请多试试几个编译器
量化分析 2014-08-31
  • 打赏
  • 举报
回复
引用 5 楼 wanght99 的回复:
[quote=引用 3 楼 wanght99 的回复:] 看了一下你这个问题, 其实是编译器作了一个处理, 我在gcc下编译, 用nm查看符号看到 $nm a.out |c++filt|grep k1 00000000006013e0 b guard variable for func1()::k1 00000000006013e8 b func1()::k1 b表示k1在bss段, 也就是"未初始化变量", 也就是说, 最后可执行文件里这是一个未初始化变量. 上面那个guard variable是编译器生成的辅助变量. 再看反汇编的函数代码:

0000000000000000 <_Z5func1v>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	53                   	push   %rbx
   5:	48 83 ec 18          	sub    $0x18,%rsp
   9:	c7 45 ec 14 00 00 00 	movl   $0x14,-0x14(%rbp)
  10:	b8 00 00 00 00       	mov    $0x0,%eax
  15:	0f b6 00             	movzbl (%rax),%eax
  18:	84 c0                	test   %al,%al
  1a:	75 30                	jne    4c <_Z5func1v+0x4c>
  1c:	bf 00 00 00 00       	mov    $0x0,%edi
  21:	e8 00 00 00 00       	callq  26 <_Z5func1v+0x26>
  26:	85 c0                	test   %eax,%eax
  28:	0f 95 c0             	setne  %al
  2b:	84 c0                	test   %al,%al
  2d:	74 1d                	je     4c <_Z5func1v+0x4c>
  2f:	8b 55 ec             	mov    -0x14(%rbp),%edx
  32:	89 d0                	mov    %edx,%eax
  34:	c1 e0 02             	shl    $0x2,%eax
  37:	01 d0                	add    %edx,%eax
  39:	c1 e0 02             	shl    $0x2,%eax
  3c:	89 05 00 00 00 00    	mov    %eax,0x0(%rip)        # 42 <_Z5func1v+0x42>
  42:	bf 00 00 00 00       	mov    $0x0,%edi
  47:	e8 00 00 00 00       	callq  4c <_Z5func1v+0x4c>
  4c:	8b 1d 00 00 00 00    	mov    0x0(%rip),%ebx        # 52 <_Z5func1v+0x52>
  52:	be 00 00 00 00       	mov    $0x0,%esi
  57:	bf 00 00 00 00       	mov    $0x0,%edi
  5c:	e8 00 00 00 00       	callq  61 <_Z5func1v+0x61>
  61:	89 de                	mov    %ebx,%esi
  63:	48 89 c7             	mov    %rax,%rdi
  66:	e8 00 00 00 00       	callq  6b <_Z5func1v+0x6b>
  6b:	be 00 00 00 00       	mov    $0x0,%esi
  70:	48 89 c7             	mov    %rax,%rdi
  73:	e8 00 00 00 00       	callq  78 <_Z5func1v+0x78>
  78:	48 83 c4 18          	add    $0x18,%rsp
  7c:	5b                   	pop    %rbx
  7d:	5d                   	pop    %rbp
  7e:	c3                   	retq   

注意2b那一行的test和后面的jne, 这是一个条件跳转, 它是通过一个辅助变量, 来指示是不是第一次进入这个函数, 如果是第一次, 就对k1变量进行赋值, 如果不是,就不管.
sorry, 应该是18行的, 总之就是另分了一个变量来记录是不是第一次调用该函数, 这样实际上是模拟出了一个静态变量初始化.[/quote] 我等要膜拜吃大神
勤奋的小游侠 2014-08-31
  • 打赏
  • 举报
回复
楼主是不是没有搞清楚const和static的中文翻译意思?
勤奋的小游侠 2014-08-31
  • 打赏
  • 举报
回复
既然是变量,自然是可以变的。 又不是常量。
xiaohuh421 2014-08-31
  • 打赏
  • 举报
回复
int y=20; static int k1=y*20; cout<<"k1 "<<k1<<endl; 你这段代码是写在main里面的吧. 静态变量是要看放在什么地方的. 你说的运行前开劈空间, 那是全局的静态变量.在所有函数体外定义的static变量. 而你在main函数中的, 则是第一次使用才分配空间并初始化,也就是运行时的. 所以输出400并不奇怪.
我看你有戏 2014-08-31
  • 打赏
  • 举报
回复
代码稍加修改,便可看本质

#include "iostream"
using namespace std;
void main()
{
	int y=20;

	for (int i=0;i<2;i++)
	{
		static int k1=y*20;
		k1++;
		cout<<"k1 "<<k1<<endl;

	}
	
	system("pause");
}

#include "iostream"
using namespace std;
void main()
{
0041C220  push        ebp  
0041C221  mov         ebp,esp 
0041C223  sub         esp,0D8h 
0041C229  push        ebx  
0041C22A  push        esi  
0041C22B  push        edi  
0041C22C  lea         edi,[ebp-0D8h] 
0041C232  mov         ecx,36h 
0041C237  mov         eax,0CCCCCCCCh 
0041C23C  rep stos    dword ptr [edi] 
	int y=20;
0041C23E  mov         dword ptr [y],14h 

	for (int i=0;i<2;i++)
0041C245  mov         dword ptr [i],0 
0041C24C  jmp         main+37h (41C257h) 
0041C24E  mov         eax,dword ptr [i] 
0041C251  add         eax,1 
0041C254  mov         dword ptr [i],eax 
0041C257  cmp         dword ptr [i],2 
0041C25B  jge         main+99h (41C2B9h) 
	{
		static int k1=y*20;
0041C25D  mov         eax,dword ptr [$S1 (459604h)] 
0041C262  and         eax,1 
0041C265  jne         main+5Fh (41C27Fh) 
0041C267  mov         eax,dword ptr [$S1 (459604h)] 
0041C26C  or          eax,1 
0041C26F  mov         dword ptr [$S1 (459604h)],eax 
0041C274  mov         eax,dword ptr [y] 
0041C277  imul        eax,eax,14h 
0041C27A  mov         dword ptr [k1 (459600h)],eax 
		k1++;
0041C27F  mov         eax,dword ptr [k1 (459600h)] 
0041C284  add         eax,1 
0041C287  mov         dword ptr [k1 (459600h)],eax 
		cout<<"k1 "<<k1<<endl;
0041C28C  push        offset std::endl (41A4D3h) 
0041C291  mov         eax,dword ptr [k1 (459600h)] 
0041C296  push        eax  
0041C297  push        offset string "k1 " (4500D0h) 
0041C29C  push        offset std::cout (459690h) 
0041C2A1  call        std::operator<<<std::char_traits<char> > (41AAB9h) 
0041C2A6  add         esp,8 
0041C2A9  mov         ecx,eax 
0041C2AB  call        std::basic_ostream<char,std::char_traits<char> >::operator<< (41A5F5h) 
0041C2B0  mov         ecx,eax 
0041C2B2  call        std::basic_ostream<char,std::char_traits<char> >::operator<< (41AAE6h) 

	}
0041C2B7  jmp         main+2Eh (41C24Eh) 
	
	system("pause");
0041C2B9  push        offset string "pause" (4500C8h) 
0041C2BE  call        @ILT+1780(_system) (41A6F9h) 
0041C2C3  add         esp,4 
}

关键看这三句汇编
0041C262  and         eax,1 
0041C265  jne         main+5Fh (41C27Fh) 
0041C267  mov         eax,dword ptr [$S1 (459604h)] 

第一次执行,ZF=1  即标志位的第七位,所以不跳转
EFL = 00000246 
1001000110
ZF=1

第二次执行,ZF=0  直接挑战执行 k1++
EFL = 00000202 
1000000010
ZF=0

459600h是K1的地址

wanght99 2014-08-30
  • 打赏
  • 举报
回复
引用 3 楼 wanght99 的回复:
看了一下你这个问题, 其实是编译器作了一个处理, 我在gcc下编译, 用nm查看符号看到 $nm a.out |c++filt|grep k1 00000000006013e0 b guard variable for func1()::k1 00000000006013e8 b func1()::k1 b表示k1在bss段, 也就是"未初始化变量", 也就是说, 最后可执行文件里这是一个未初始化变量. 上面那个guard variable是编译器生成的辅助变量. 再看反汇编的函数代码:

0000000000000000 <_Z5func1v>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	53                   	push   %rbx
   5:	48 83 ec 18          	sub    $0x18,%rsp
   9:	c7 45 ec 14 00 00 00 	movl   $0x14,-0x14(%rbp)
  10:	b8 00 00 00 00       	mov    $0x0,%eax
  15:	0f b6 00             	movzbl (%rax),%eax
  18:	84 c0                	test   %al,%al
  1a:	75 30                	jne    4c <_Z5func1v+0x4c>
  1c:	bf 00 00 00 00       	mov    $0x0,%edi
  21:	e8 00 00 00 00       	callq  26 <_Z5func1v+0x26>
  26:	85 c0                	test   %eax,%eax
  28:	0f 95 c0             	setne  %al
  2b:	84 c0                	test   %al,%al
  2d:	74 1d                	je     4c <_Z5func1v+0x4c>
  2f:	8b 55 ec             	mov    -0x14(%rbp),%edx
  32:	89 d0                	mov    %edx,%eax
  34:	c1 e0 02             	shl    $0x2,%eax
  37:	01 d0                	add    %edx,%eax
  39:	c1 e0 02             	shl    $0x2,%eax
  3c:	89 05 00 00 00 00    	mov    %eax,0x0(%rip)        # 42 <_Z5func1v+0x42>
  42:	bf 00 00 00 00       	mov    $0x0,%edi
  47:	e8 00 00 00 00       	callq  4c <_Z5func1v+0x4c>
  4c:	8b 1d 00 00 00 00    	mov    0x0(%rip),%ebx        # 52 <_Z5func1v+0x52>
  52:	be 00 00 00 00       	mov    $0x0,%esi
  57:	bf 00 00 00 00       	mov    $0x0,%edi
  5c:	e8 00 00 00 00       	callq  61 <_Z5func1v+0x61>
  61:	89 de                	mov    %ebx,%esi
  63:	48 89 c7             	mov    %rax,%rdi
  66:	e8 00 00 00 00       	callq  6b <_Z5func1v+0x6b>
  6b:	be 00 00 00 00       	mov    $0x0,%esi
  70:	48 89 c7             	mov    %rax,%rdi
  73:	e8 00 00 00 00       	callq  78 <_Z5func1v+0x78>
  78:	48 83 c4 18          	add    $0x18,%rsp
  7c:	5b                   	pop    %rbx
  7d:	5d                   	pop    %rbp
  7e:	c3                   	retq   

注意2b那一行的test和后面的jne, 这是一个条件跳转, 它是通过一个辅助变量, 来指示是不是第一次进入这个函数, 如果是第一次, 就对k1变量进行赋值, 如果不是,就不管.
sorry, 应该是18行的, 总之就是另分了一个变量来记录是不是第一次调用该函数, 这样实际上是模拟出了一个静态变量初始化.
我看你有戏 2014-08-30
  • 打赏
  • 举报
回复
静态变量一次定义的地方,执行一次,下一次执行的时候直接跳过,因为已经在内存中了 你这里感觉是有编译优化了 int y=20 下一句就是static 编译的时候看到y没变化,那么就直接算出400变成一个立即数
taodm 2014-08-29
  • 打赏
  • 举报
回复
请多试几个编译器。
wanght99 2014-08-29
  • 打赏
  • 举报
回复
看了一下你这个问题, 其实是编译器作了一个处理, 我在gcc下编译, 用nm查看符号看到 $nm a.out |c++filt|grep k1 00000000006013e0 b guard variable for func1()::k1 00000000006013e8 b func1()::k1 b表示k1在bss段, 也就是"未初始化变量", 也就是说, 最后可执行文件里这是一个未初始化变量. 上面那个guard variable是编译器生成的辅助变量. 再看反汇编的函数代码:

0000000000000000 <_Z5func1v>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	53                   	push   %rbx
   5:	48 83 ec 18          	sub    $0x18,%rsp
   9:	c7 45 ec 14 00 00 00 	movl   $0x14,-0x14(%rbp)
  10:	b8 00 00 00 00       	mov    $0x0,%eax
  15:	0f b6 00             	movzbl (%rax),%eax
  18:	84 c0                	test   %al,%al
  1a:	75 30                	jne    4c <_Z5func1v+0x4c>
  1c:	bf 00 00 00 00       	mov    $0x0,%edi
  21:	e8 00 00 00 00       	callq  26 <_Z5func1v+0x26>
  26:	85 c0                	test   %eax,%eax
  28:	0f 95 c0             	setne  %al
  2b:	84 c0                	test   %al,%al
  2d:	74 1d                	je     4c <_Z5func1v+0x4c>
  2f:	8b 55 ec             	mov    -0x14(%rbp),%edx
  32:	89 d0                	mov    %edx,%eax
  34:	c1 e0 02             	shl    $0x2,%eax
  37:	01 d0                	add    %edx,%eax
  39:	c1 e0 02             	shl    $0x2,%eax
  3c:	89 05 00 00 00 00    	mov    %eax,0x0(%rip)        # 42 <_Z5func1v+0x42>
  42:	bf 00 00 00 00       	mov    $0x0,%edi
  47:	e8 00 00 00 00       	callq  4c <_Z5func1v+0x4c>
  4c:	8b 1d 00 00 00 00    	mov    0x0(%rip),%ebx        # 52 <_Z5func1v+0x52>
  52:	be 00 00 00 00       	mov    $0x0,%esi
  57:	bf 00 00 00 00       	mov    $0x0,%edi
  5c:	e8 00 00 00 00       	callq  61 <_Z5func1v+0x61>
  61:	89 de                	mov    %ebx,%esi
  63:	48 89 c7             	mov    %rax,%rdi
  66:	e8 00 00 00 00       	callq  6b <_Z5func1v+0x6b>
  6b:	be 00 00 00 00       	mov    $0x0,%esi
  70:	48 89 c7             	mov    %rax,%rdi
  73:	e8 00 00 00 00       	callq  78 <_Z5func1v+0x78>
  78:	48 83 c4 18          	add    $0x18,%rsp
  7c:	5b                   	pop    %rbx
  7d:	5d                   	pop    %rbp
  7e:	c3                   	retq   

注意2b那一行的test和后面的jne, 这是一个条件跳转, 它是通过一个辅助变量, 来指示是不是第一次进入这个函数, 如果是第一次, 就对k1变量进行赋值, 如果不是,就不管.
赵4老师 2014-08-29
  • 打赏
  • 举报
回复
“变量赋值”和“变量初始化”不是一回事! “变量赋值”发生在运行期,其写法遵循赋值语法规定。 “变量初始化”发生在编译期或运行期,其写法遵循初始化列表语法规定。
熊熊大叔 2014-08-29
  • 打赏
  • 举报
回复
你说的是c的初始化。 c++的初始化不一定是在编译时完成的,可以在运行中动态初始化。

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧