本文介绍C/C++中变量存储的位置:包括 全局变量,静态局部变量,堆变量
#include<stdio.h>
int g_variable1 = 12345;
int g_variable2 = 45678;
int main()
{
int one =1,two =2;
scanf("%d,%d",&one,&two);
printf("%d,%d\n",one,two);
scanf("%d,%d",&g_variable1,&g_variable2);
printf("%d,%d\n",g_variable1,g_variable2);
return 0;
}
编译后的汇编代码
_DATA SEGMENT
_g_variable1 DD 03039H
_g_variable2 DD 0b26eH
_DATA ENDS
由上一部分可知 全局变量在data段中
CONST SEGMENT
??_C@_05BBIB@?$CFd?0?$CFd?$AA@ DB '%d,%d', 00H ; `string'
CONST ENDS
; COMDAT ??_C@_06JDIH@?$CFd?0?$CFd?6?$AA@
CONST SEGMENT
??_C@_06JDIH@?$CFd?0?$CFd?6?$AA@ DB '%d,%d', 0aH, 00H ; `string'
CONST ENDS
; COMDAT _main
_TEXT SEGMENT
_one$ = -4
_two$ = -8
_main PROC NEAR ; COMDAT
; 6 : {
push ebp
mov ebp, esp
sub esp, 72 ; 00000048H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-72]
mov ecx, 18 ; 00000012H
mov eax, -858993460 ; ccccccccH
rep stosd
; 7 : int one =1,two =2;
mov DWORD PTR _one$[ebp], 1 ;这里存one
mov DWORD PTR _two$[ebp], 2 ;这里存two
; 8 : scanf("%d,%d",&one,&two);
lea eax, DWORD PTR _two$[ebp]
push eax
lea ecx, DWORD PTR _one$[ebp]
push ecx
push OFFSET FLAT:??_C@_05BBIB@?$CFd?0?$CFd?$AA@ ; `string'
call _scanf
add esp, 12 ; 0000000cH
; 9 : printf("%d,%d\n",one,two);
mov edx, DWORD PTR _two$[ebp]
push edx
mov eax, DWORD PTR _one$[ebp]
push eax
push OFFSET FLAT:??_C@_06JDIH@?$CFd?0?$CFd?6?$AA@ ; `string'
call _printf
add esp, 12 ; 0000000cH
; 10 : scanf("%d,%d",&g_variable1,&g_variable2);
push OFFSET FLAT:_g_variable2
push OFFSET FLAT:_g_variable1
push OFFSET FLAT:??_C@_05BBIB@?$CFd?0?$CFd?$AA@ ; `string'
call _scanf
add esp, 12 ; 0000000cH
; 11 : printf("%d,%d\n",g_variable1,g_variable2);
mov ecx, DWORD PTR _g_variable2
push ecx
mov edx, DWORD PTR _g_variable1
push edx
push OFFSET FLAT:??_C@_06JDIH@?$CFd?0?$CFd?6?$AA@ ; `string'
call _printf
add esp, 12 ; 0000000cH
由上代码发现:全局变量在数据区,生命周期与模块一致,使用立即数访问;
局部变量在栈区,使用ebp或esp访问(优化后会使用esp访问)
问题:关于局部静态变量:存储位置?初始化方式?
C语言中是不允许对局部静态变量用非常量赋初值的,C++中允许使用
#include<iostream>
void func(int a)
{
static int b = a;
}
int main()
{
int a;
func(a);
return 0;
}
以下是func中对应的汇编实现
; 4 : static int b = a;
xor eax, eax
mov al, BYTE PTR _?$S25@?1??func@@YAXH@Z@4EA
and eax, 1 //eax 与1 做位与运算,
test eax, eax
jne SHORT $L7353 //测试,不等跳转
mov cl, BYTE PTR _?$S25@?1??func@@YAXH@Z@4EA
or cl, 1
mov BYTE PTR _?$S25@?1??func@@YAXH@Z@4EA, cl //将 那个地址赋1
mov edx, DWORD PTR _a$[ebp]
mov DWORD PTR _?b@?1??func@@YAXH@Z@4HA, edx //对 b 赋值
$L7353:
; 5 : }
由上可知,比较的标志位是用来让static变量初始化一次的,如果该位为1 ,则说明已经初始化,不需要再初始化。
关于堆变量:数据在new或malloc时,返回数据在堆中的地址,具体读者请自行实验。