⑴ GCC編譯器局部變數地址分配為什麼總是從低
原因:GCC的堆棧保護技術—— canary的使用。
使用的原因是為了防止某些溢出的攻擊。但是只是溢出時方向發生了改變,並沒有起到太大的作用,可能對於傳統的一些攻擊方法有用。
GCC 中的堆棧保護實現
Stack Guard 是第一個使用 Canaries 探測的堆棧保護實現,它於 1997 年作為 GCC 的一個擴展發布。最初版本的 Stack Guard 使用 0x00000000 作為 canary word。盡管很多人建議把 Stack Guard 納入 GCC,作為 GCC 的一部分來提供堆棧保護。但實際上,GCC 3.x 沒有實現任何的堆棧保護。直到 GCC 4.1 堆棧保護才被加入,並且 GCC4.1 所採用的堆棧保護實現並非 Stack Guard,而是 Stack-smashing Protection(SSP,又稱 ProPolice)。
SSP 在 Stack Guard 的基礎上進行了改進和提高。它是由 IBM 的工程師 Hiroaki Rtoh 開發並維護的。與 Stack Guard 相比,SSP 保護函數返回地址的同時還保護了棧中的 EBP 等信息。此外,SSP 還有意將局部變數中的數組放在函數棧的高地址,而將其他變數放在低地址。這樣就使得通過溢出一個數組來修改其他變數(比如一個函數指針)變得更為困難。
⑵ (C語言)編譯時給全局變數和靜態變數分配存儲空間,運行時給局部變數分配存儲空間,這樣說對嗎
全局變數,靜態局部變數,靜態全局變數都在靜態存儲區分配空間,而局部變數在棧里分配空間
全局變數本身就是靜態存儲方式, 靜態全局變數當然也是靜態存儲方式。這兩者在存儲方式上並無不同。這兩者的區別雖在於非靜態全局變數的作用域是整個源程序,當一個源程序由多個源文件組成時,非靜態的全局變數在各個源文件中都是有效的。而靜態全局變數則限制了其作用域,即只在定義該變數的源文件內有效,在同一源程序的其它源文件中不能使用它。由於靜態全局變數的作用域局限於一個源文件內,只能為該源文件內的函數公用,因此可以避免在其它源文件中引起錯誤。
⑶ c編譯原理,如何處理同名局部變數和全局變數
定義就不說了,位置不同就有區別了,只說訪問——若全局變數和局部變數都名為a,則在既可訪問全局變數又可訪問局部變數的地方,訪問全局變數用::a,訪問局部變數直接用a。
⑷ C語言中的 局部變數,存儲在什麼地方
C語言中的局部變數存儲在棧里。
普通的局部變數在棧空間上分配,這個局部變數所在的函數被多次調用時,每次調用這個局部變數在棧上的位置都不一定相同。局部變數也可以在堆上動態分配(malloc),但是記得使用完這個堆空間後要釋放之。
在棧空間上分配時是要注意內存的,不能分配內存過大。如果棧內空間小於所申請的空間大小,那麼這時系統將揭示棧溢出,並給出相應的異常信息。但是堆不一樣,堆可分配空間是很大的。
(4)編譯局部變數擴展閱讀
局部變數分類
1、位置:靜態局部變數被編譯器放在全局存儲區.data,所以它雖然是局部的,但是在程序的整個生命周期中存在(定義時出生,隨著程序結束而結束)。
2、訪問許可權:靜態局部變數只能被其作用域內的變數或函數訪問。也就是說雖然它會在程序的整個生命周期中存在,由於它是static的,它不能被其他的函數和源文件訪問。
3、值:靜態局部變數如果沒有被用戶初始化,則會被編譯器自動賦值為0,以後每次調用靜態局部變數的時候都用上次調用後的值。
⑸ 編譯器對作為局部變數的數組是怎麼管理的放在堆棧中
C語言的堆跟棧是有區別的,請大家不要混淆。
局部變數和函數調用時的實參是放在棧里。所以有大家常說函數調用時的入棧,出桟這個說話。
動態申請的內存放在堆里的。
全局變數和靜態變數是放在另外的全局內存區。
⑹ 局部變數為什麼在編譯時無法確定
編譯時能確定的只是常量(PE放到data區),其他所有的都要等到堆棧分配(運行時),局部變數更是要等到所在函數或類分配後才能進行分配的
⑺ 操作系統和編譯器是怎麼識別全局變數和局部
操作系統,只管調度進程,線程編譯器根據編程語言的定義,確定變數的作用於,存儲類型,生命周期!
定義在函數外部的變數,只有文件靜態變數,和外部變數
外部變數,是實實在在的全局變數,不論作用域還是生命周期。
靜態變數是局部作用域的,生命周期為,程序的生命周期的變數。
自動變數和函數參數,是局部作用域的生命周期為函數結束的局部變數。
寄存器變數,用register定義,是局部變數;
函數內部的靜態變數,語句組內部的靜態變數,局部作用域的,生命周期為,程序的生命周期的變數。
靜態變數,編譯器,可以通過static關鍵字知道。
自動變數,1)函數內部定義的非靜態變數,非寄存器變數是自動變數。
2)函數參數,只能是自動變數,不過也可能定義在寄存器中。
這和調用約定有關,因此不可以用register定義。
C語言沒有全局變數這種數據類型。
只有4種存儲類型,和變數的作用域與生命周期的概念。
C++同樣沒有全局變數這種數據類型。
有另外的兩種作用域
1)namespace作用域。
2)類(類型)作用域。
C只有全局,文件,函數以及函數內部的語句組,4種逐漸縮小的作用域。
其中內層,對外部作用域,具有完全的遮蔽作用。
C++可以通過作用域限定符,區分不同作用域(類,名空間)的名字。
類作用域,可以通過訪問許可權,限制外部的訪問權。
函數作用域(語句組作用域)是封閉的作用域,外部不可以使用函數內部定義的名字。
也不會和外部有命名沖突,只會遮蔽外部的名字。
類作用於,和名空間由於訪問方式不同,命名沖突和遮蔽有些特殊。
函數和全局域,基本不會和類作用域有命名沖突,除非類方法內部。
命名空間,可以避免命名沖突。
類繼承體系中,則有遮蔽現象。
還有訪問許可權問題。
實際上,全局變數,有兩個概念可以判定
1)作用域(空間)===>由定義和聲明位置,和定義和聲明使用的關鍵字決定。
2)生命周期(時間)===>外部和靜態變數,的生命周期是全局的,從初始化到程序結束。
函數參數,和函數局部非靜態變數,是局部變數
函數參數的傳遞,是跨函數的(實參,變成形參);
函數內部定義的,局部變數,只有定義處可見,作用域是函數甚至語句組局部,
其中靜態變數,生命周期是全局的,非靜態是函數甚至語句組的。
全局變數,不是C,C++的概念。
而是,使用編程語言的程序員的概念。
所以,全局變數和C,C++的存儲類型,作用域,生命周期等,不是一一對應的概念。
所以,可以有不同的理解。
所以這個概念是很模糊的,不清晰的。
比如局部靜態變數,類的靜態變數,是否全局變數,就不是可以清晰的說明的。
⑻ C語言中的「局部變數」是什麼意思
C語言全局變數和局部變數
引子---
? ?? ???變數可以在程序中三個地方說明: 函數內部、函數的參數定義中或所有的函數外部。根據所定義位置的不同, 變數可分為局部變數、形式參數和全程變數。從空間角度來看,變數可以分為全局變數和局部變數,而從時間角度來分的 可以有靜態存儲變數和動態存儲變數之分。
一。全局變數和局部變數
1。局部變數
他是 指在函數內部定義的變數 作用域為定義局部變數的函數 也就是說他只能在定義他的函數中使用
最值得注意的是 只有在程序執行到定義他的模塊時才能生成,一旦執行退出該模塊則起變數消失
eg.
func ()
{
? ?int x;? ?局部變數x的作用域 很明確
? ?......
}
2。全局變數
在程序執行的過程中一直有效
eg.
int x=1;
func ()
{
? ?x=x+1;
}
func1 ()
{
??x=x-1;
}
main ()
{
}
由此不難看出整型x的作用范圍
對於全局變數 如果在定義的時候不做初始化 則系統將自動為起賦值 數值型為0
字元型為空'\0'
全局變數的弊端 增加內存開銷 降低函數的通用性
定義全局變數時 理想的位置是在文件的開頭 當這些函數以及同一個程序中的其他源程序文件中的某些函數需要使用該全局變數時 在函數內部對該變數使用extern 加以說明 說明他是外部的
(這里還要做詳細的講解)
eg.
main ()
{
extern int a,b;
printf ("mIn is %d\n",min(a,b));
}
int a=1,b=2;
int min (x,y)
int x,y;
{
int z;
z=x<y?x:y;
return(z);
}
我還要說明的是 對外部變數的說明和對全局變數的定義不是一回事
對外部變數的說明 只是聲明該變數是在外部定義過的一個全局變數 在這里引用 而對全局變數的定義則是要對起分配存儲單元的
一個全局變數只能定義一次 可是卻可以多次引用
*** 在同一源文件中,全局變數和局部變數同名時,在局部變數的作用域內,全局變數不起作用的。
二。靜態存儲變數和動態存儲變數
對於程序運行期間根據需要進行臨時動態分配存儲空間的變數 為動態存儲變數
對於那些程序運行期間永久佔用固定內存的變數 稱為靜態存儲變數
還要說明的是 程序的指令代碼是存放在程序代碼區的 靜態存儲變數是存放在靜態數據區的 包括全局變數等 而程序中的動態存儲變數存放在動態數據區 如函數的形參以及函數調用時的返回地址等
三。C語言中的變數存儲分類指定
? ?
? ? auto
? ? auto稱為自動變數 如果函數不做其他說明的話 均為自動變數
? ? static
? ? static稱為靜態變數。根據變數的類型可以分為靜態局部變數和靜態全程變數。
? ? 1. 靜態局部變數
? ?
? ???它與局部變數的區別在於: 在函數退出時, 這個變數始終存在, 但不能被其它函數使用, 當再次進入該函數時, 將保存上次的結果。其它與局部變數一樣。
? ?
? ? 2. 靜態全程變數
? ?
? ???Turbo C2.0允許將大型程序分成若干獨立模塊文件分別編譯, 然後將所有模塊的目標文件連接在一起, 從而提高編譯速度, 同時也便於軟體的管理和維護。靜態全程變數就是指只在定義它的源文件中可見而在其它源文件中不可見的變數。它與全程變數的區別是: 全程變數可以再說明為外部變數(extern), 被其它源文件使用, 而靜態全程變數卻不能再被說明為外部的, 即只能被所在的源文件使用。
? ?
? ?
? ? extern
? ? extern稱為外部變數。為了使變數除了在定義它的源文件中可以使用外, 還要被其它文件使用。因此,? ?必須將全程變數通知每一個程序模塊文件,? ?此時可用extern來說明。
eg.
? ?? ???文件1為file1.c? ?? ?? ?? ?? ?? ?文件2為file2.c
? ? int i, j;/*定義全程變數*/? ?? ???extern int i, j;/*說明將i, j從
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???文件1中復制過來*/
? ? char c;? ?? ?? ?? ?? ?? ?? ?? ???extern char c; /*將c復制過來*/
? ? void func1(int k);? ?? ?? ?? ?? ?func2()? ?? ???/*用戶定義函數*/
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? {
? ? main()? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?static float k;/*定義靜態變數*/
? ? {? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???i=j*5/100;
? ?? ?? ? func1(20);/*調用函數*/? ?? ???k=i/1.5;
? ?? ?? ? func2();? ?? ?? ?? ?? ?? ?? ?? ?? ?.
? ?? ?? ? .? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? .
? ?? ?? ? .? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? .
? ?? ?? ? .? ?? ?? ?? ?? ?? ?? ?? ?? ? }
? ???}
? ???func1(int k) /*用戶定義函數*/
? ???{
? ?? ?? ? j=k*100;
? ???}
? ? 對於以上兩個文件file1.c和file2.c, 用Turbo C2.0的集成開發環境進行編譯
連接時, 首先應建立一個.prj的文件。例如file.prj, 該文件內容如下:
? ???file1.c
? ???file2.c
? ? 然後將file.prj的文件名寫入主菜單Project中的Project Name項中。 再用F9
編譯連接, 就可產生一個文件名為fioe.exe的可執行文件。
? ???
??
? ? register
? ? register稱為寄存器變數。它只能用於整型和字元型變數。定義符register說明的變數被Turbo C2.0存儲在CPU的寄存器中,??而不是象普通的變數那樣存儲在內存中, 這樣可以提高運算速度。但是Turbo C2.0隻允許同時定義兩個寄存器變數,一旦超過兩個, 編譯程序會自動地將超過限制數目的寄存器變數當作非寄存器變數來處理。因此, 寄存器變數常用在同一變數名頻繁出現的地方。
? ? 另外, 寄存器變數只適用於局部變數和函數的形式參數, 它屬於auto型變數,
因此, 不能用作全程變數。定義一個整型寄存器變數可寫成:
? ?? ?register int a;
? ? 對於以上所介紹的變數類型和變數存儲類型將會在以後的學習中, 通過例行程序中的定義、使用來逐漸加深理解。
⑼ 全局變數和局部變數有什麼區別是怎麼實現的
1、 全局變數的作用用這個程序塊,而局部變數作用於當前函數;
2、前者在內存中分配在全局數據區,後者分配在棧區;
3、 生命周期不同:全局變數隨主程序創建和創建,隨主程序銷毀而銷毀,局部變數在局部函數內部,甚至局部循環體等內部存在,退出就不存在;
4、 使用方式不同:通過聲明後全局變數程序的各個部分都可以用到,局部變數只能在局部使用
操作系統和編譯器通過內存分配的位置來知道的全局變數分配在全局數據段,並且在程序被運行的時候就被載入。;
編譯器通過語法詞法的分析,判斷出是全局變數還是局部變數。如果是全局變數的話,編譯器在將源代碼翻譯成二進制代碼時就為全局變數分配好一個虛擬地址 (windows下0x00400000以上的地址,也就是所說的全局區),所以程序在對全局變數的操作時是對一個硬編碼的地址操做。
局部變數的話,編譯時不分配空間,而是以相對於ebp或esp的偏移來表示局部變數的地址,所以局部變數內存是在局部變數所在的函數被調用時才真正分配。 以匯編的角度來看:函數執行時,局部變數在棧中分配,函數調用完畢釋放局部變數對應的內存,另外局部變數可以直接分配在寄存器中。
操作系統通過變數的分配地址就可以判斷出是局部變數和全局變數。
⑽ 編譯器怎麼知道是全局變數還是局部變數
這個要細說,能說的很詳細,我說一下,比較好理解的你就懂了!
我說之前先打個比方:小區人家,幾十戶,每家每戶都有燈光自己用就是局部的
月亮..全局的.都能用懂了?
按照目前的面向對象來說如Java,C++,C#,Ruby中,由於變數都是封裝在類裡面的,對別的類不可見,所以已經幾乎完全拋棄了全局變數的概念。然而,可以通過把一個類定義為public static,把類成員變數也定義為public static,使該變數在內存中佔用固定、唯一的一塊空間,來實現全局變數的功能。
說通俗點,你如果想理解,就假如在一個類中,看你定義的變數,位置!類中,方法外面,就屬於全局,每個方法都能拿去用..方法裡面定義的,就屬於局部的,只能他自己用.懂了?
和你一樣初學者,不足之處還請指點!