
8種機械鍵盤軸體對比
本人程式員,要買一個寫代碼的鍵盤,請問紅軸和茶軸怎麼選?
static修飾局部變量
首先來看一段程式,思考一下該程式調用foo、bar函數後輸出a的值分别會是多少呢?
123456789101112131415161718192021#include
int main(){
foo();
bar();
foo();
bar();
return 0;
}
void foo() {
static int a = 0x12345678;
++a;
printf("a in foo(), location: 0x%x, current value: 0x%xn", &a, a);
}
void bar() {
static int a = 0x87654321;
++a;
printf("a in bar(), location: 0x%x, current value: 0x%xn", &a, a);
}
使用gcc編譯上面的程式,運作程式,控制台輸出如下圖
從程式的輸出我們可以看到foo和bar中的a的存儲位址不同,而且每次調用foo和bar,它們自己的變量a的值都增加了1。再來看一下它們的反彙編代碼
可以看到a并不在棧上。使用objdump -h Test.exe獲得各個段的資訊。可以看到.data段将被加載到0000000000403000處,它和列印出來的變量a的存儲位址很接近。猜測變量a可能就在.data段。Test.exe: file format pei-x86-64
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00001db8 0000000000401000 0000000000401000 00000600 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE, DATA
1 .data 000000a8 0000000000403000 0000000000403000 00002400 2**4
CONTENTS, ALLOC, LOAD, DATA
2 .rdata 00000830 0000000000404000 0000000000404000 00002600 2**4
CONTENTS, ALLOC, LOAD, READONLY, DATA
3 .pdata 00000288 0000000000405000 0000000000405000 00003000 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
4 .xdata 0000023c 0000000000406000 0000000000406000 00003400 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
5 .bss 00000a50 0000000000407000 0000000000407000 00000000 2**6
ALLOC
6 .idata 00000818 0000000000408000 0000000000408000 00003800 2**2
CONTENTS, ALLOC, LOAD, DATA
7 .CRT 00000068 0000000000409000 0000000000409000 00004200 2**3
CONTENTS, ALLOC, LOAD, DATA
8 .tls 00000068 000000000040a000 000000000040a000 00004400 2**5
CONTENTS, ALLOC, LOAD, DATA
9 .debug_aranges 00000450 000000000040b000 000000000040b000 00004600 2**4
CONTENTS, READONLY, DEBUGGING
10 .debug_info 0000c127 000000000040c000 000000000040c000 00004c00 2**0
CONTENTS, READONLY, DEBUGGING
11 .debug_abbrev 00001b04 0000000000419000 0000000000419000 00010e00 2**0
CONTENTS, READONLY, DEBUGGING
12 .debug_line 00001864 000000000041b000 000000000041b000 00012a00 2**0
CONTENTS, READONLY, DEBUGGING
13 .debug_frame 00000ba8 000000000041d000 000000000041d000 00014400 2**3
CONTENTS, READONLY, DEBUGGING
14 .debug_str 00000300 000000000041e000 000000000041e000 00015000 2**0
CONTENTS, READONLY, DEBUGGING
15 .debug_loc 00002c70 000000000041f000 000000000041f000 00015400 2**0
CONTENTS, READONLY, DEBUGGING
16 .debug_ranges 00000520 0000000000422000 0000000000422000 00018200 2**0
CONTENTS, READONLY, DEBUGGING
接下來确認變量a是不是在.data段。
使用指令objdump -s -j .data Test.exe檢視.data段的内容,可以看到如下的輸出
果然在403010這一行看到了foo和bar兩個函數裡的a的兩個初始值,說明本例中的static局部變量存儲在.data段。
至此我們可以看出,當static修飾局部變量時,這個變量将會存儲于靜态資料區。且這個變量的作用域沒有發生變化,仍然限于函數(子產品)内部。
static修飾函數
測試代碼mod1.c和mod2.c如下
mod1.c
123static int foo() {
return 1;
}
mod2.c
12345678#include
extern int foo();
int main() {
printf(foo());
return 0;
}
輸入gcc mod1.c mod2.c 指令,控制台輸出如下:mod2.c:(.text+0xe): undefined reference to `foo’
collect2.exe: error: ld returned 1 exit status
這表明gcc在連結的時候找不到符号foo,因為mod1.c中的foo函數在mod2.c中不可見。
接下來修改mod2.c
12345678910#include
static int foo() {
return 2;
}
int main() {
printf(foo());
return 0;
}
再次編譯連結,沒有出現錯誤。運作程式,控制台輸出了2;也就是說mod2.c中調用的foo()位于mod2.c而非mod1.c。
以上現象表明,在C語言中,函數預設是全局的,static修飾函數時會使該函數的作用域被限制在了定義該變量的源檔案内。
static修飾全局變量
其效果和修飾函數時相同,不再贅述。
總結static修飾局部變量會使該變量存儲于靜态資料區。
沒有使用static修飾的全局變量或函數在所有子產品都可見,而使用static修飾的全局變量或函數隻在目前子產品可見(隻在定義該變量或函數的源檔案内有效)。static改變了全局變量或函數預設的作用域。