標籤:

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++中,模板元編程有哪些更方便的寫法?

TAG:C編程語言 | CC |