C語言 static char str[] 的問題?
初學c語言,在一次測試static 聲明的字元數組中想到:如果我一個程序多次調用一個其中有局部靜態變數的方法,不就造成多次聲明的情況了?會不會造成生成多個靜態變數?
經過測試:多次調用static char str[]
結果指針沒有變化,說明不會生成多個靜態變數
int main(){
fun("aa");
fun("bbb");
}
int fun(char* k){
static char str[4];//將靜態數組大小設置為4
strcpy(str,k);
printf("發送參數大小:%d
",strlen(k));
printf("當前靜態大小:%d
",sizeof(str));
printf("%s
",str);
printf("%p
",str);
}結果:
發送參數大小:2
當前靜態大小:4
aa
00405008
發送參數大小:3
當前靜態大小:4
bbb
00405008然後問題來了,就算我將靜態變數設置為
static char str[0]
最終測試輸出字元串的結果還是正確的?
這個靜態變數到底是什麼機制?我要怎麼聲明才是正確的?求大神解惑?
設置成str[0]還能work是因為你緩衝區溢出攻擊了自己而已,沒有什麼奇怪的。不知道題主到底想問什麼。但是static變數其實就等於全局變數,只是順手給你加上了初始化時機和scope的限制。
多讀讀相應的標準文獻就知道了。
函數內的static變數就是只限本函數能看到的全局變數,所以當然只有一份,也不存在重複聲明。局部static變數的初始化時機是第一次執行到初始化語句的時候。
局部static變數是個很深的水坑,因為無論是遞歸調用,還是多線程調用,這個變數統統只有一份。不留心的話很容易坑死你。
至於char str[0],那是緩衝區溢出,沒出錯只是看起來沒出錯,指不定哪裡就被你寫壞了。
1.
未初始化的static變數內存會被存在.bss section,並不是堆棧這樣的動態內存空間。
(鏈接生成的程序映象中實際為沒有該變數分配空間,只是做了一個大小記號,.bss只有裝載的時候才會被程序初始化置零)
//test.c
#include &
void fun() {
static int m;
}
int main() {
return 0;
}
2.
初始化的static變數,存在.data section中
//test.c
#include &
int fun() {
static int m = 10;
return m;
}
int main() {
return 0;
}
//編譯
gcc test.c -o test
//反編譯
objdump -d test
...
00000000004004f6 &
4004f6: 55 push %rbp
4004f7: 48 89 e5 mov %rsp,%rbp
4004fa: 8b 05 38 0b 20 00 mov 0x200b38(%rip),%eax # 601038 &
400500: 5d pop %rbp
400501: c3 retq
...
//從上可見m的內存在601038處
//查看內存
objdump -s test
...
Contents of section .data:
601028 00000000 00000000 00000000 00000000 ................
601038 0a000000 ....
...
//0a是16進位,也就是十進位數字10
這個m變數地址就是 601038,可知道static修飾的變數地址空間不是在程序運行時才分配的
3.
初始化和賦值
#include &
int fun(int a, int b) {
static int m = a + b;
return m;
}
int main() {
printf("%d
", fun(0,3));
printf("%d
", fun(2,3));
return 0;
}
這段代碼我用gcc5.4沒有編譯過,按照網上的說法應該是c99標準規定,靜態變數必須用常量表達式或字元串字面量進行初始化(這個我具體沒有查證)
但是用g++當成cpp編譯過了,運行看到兩次輸出都是3,也就是初始化只做了一次
#include &
int fun(int a, int b) {
static int m; // 或者 static int m = 1;
m = a + b;
return m;
}
int main() {
printf("%d
", fun(0,3));
printf("%d
", fun(2,3));
return 0;
}
輸出3和5,這裡就是單純的賦值
4.
static char str[0]
這種行為很危險,程序很有可能暫時不會崩潰繼續運行下去,從而引發緩衝區溢出攻擊
從這一點上可以看出c語言是弱類型語言
我好像沒回答到點子上!!!我要去努力搬磚去了。。。
函數內的static變數會在數據段,bss段分配空間而不是棧編譯器給你了一個合法的地址,只不過編譯器沒指望你往裡寫東西然後你把數據段里寫了垃圾進去。
但是地址是合法的,可以寫也可以讀
一般情況下受害者是其他使用數據段的人這種情況比較難構造傳統意義上的緩衝區溢出靜態變數類似於聲明在全局空間。只不過有作用域的限制。
只在第一次聲明的時候分配儲存空間並只初始化一次。(●—●)
我的理解是,聲明在函數裡面的話,在函數第一次被調用時分配空間並初始化。聲明在外面的話,在main函數執行前就完成了初始化工作。另外還有scope的事:假如同時在函數里外聲明了兩個同類型同名的static變數,函數裡面在使用這個變數時,函數內部變數的優先順序高於外部變數的。所以結論是怎麼寫都可以。
推薦閱讀:
※第16集:旋轉重置視圖『Photoshop CC 2017 one-on-one基礎篇』
※第05集:在Photoshop或Bridge中打開圖片『Photoshop CC 2017 one-on-one基礎篇』
※新手自學c++,推薦一些編譯器?
※第90集:使用快速選擇工具『Photoshop CC 2017 one-on-one基礎篇』
※在modern c++中,模板元編程有哪些更方便的寫法?