本文介紹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時,返回數據在堆中的地址,具體讀者請自行實驗。