看板 C_and_CPP 關於我們 聯絡資訊
我先說結論, 你在 auto 那裡看到的「動態」、「靜態」的修飾全都拿掉, 一方面他的語意讓大多學子誤會 (我相信筆者本意也不是如此), 另一方面照他邏輯走也不完全正確。 由於這本書我沒全看完 (其中一個原因是我覺得有時敘述會讓人有點誤解) 我們暫時拋棄你手邊書本的語意,換個說法來過。 同時我也只針對你書本之文意做部份說明,太深入的我就不再多敘述, 所以 register、static、global variable、constant 並不在此文探討範圍內。 ---- ※ 引述《amozartea (單車單車)》之銘言: : 如題,這可能很少人問過 : 書上寫說區域變數其實都自動預設auto, : 在編譯過程中並不會配置一塊記憶體空間,而是在程式執行時以堆疊的方式存放, : 因此他是屬於動態的變數。 : ^^^^^^^^^^^^^^^^^^^^^^ 此段是出自洪維恩的書 這段省略了很多東西,洽巧初學者可能也不要知道會比較好, 因為可能會打擊學習程式的信心。 下面五行很重要,請記起來,沒記起來的話這篇文章你看不懂。 一個最重要、基本的觀念是:不論程式裡面的變數宣告成怎樣, 最終都會被放在記憶體裡面,而程式在執行時,這些記憶 體又被畫分為若干區段,其中你書本提到的是 stack (堆疊段) 與 heap (這個怎麼翻?) , 這兩個名詞以後請用英文寫出來, 我相信會比中文表達深切很多。 原文這段有四個字是重點: 編譯過程 ,指的是 編譯期 也就是上面這些動作是你在使用 dev-c++ / vc / gcc 等編譯器時, 就決定動作這些變數是要放 堆疊 段。 ----- 引言 1 在編譯過程中並不會配置一塊記憶體空間, 而是在程式執行時以堆疊的方式存放,因此他是屬於動態的變數。 若照 C language 之定義,local variable 加 auto 時,其實有寫跟沒寫是一樣的。 也就是說 { int i; // auto int i; 同義 int arr[3]={1,2,3}; // auto int arr[3]={1,2,3}; 同義 int *ptr=NULL; // auto int* ptr=NULL; 同義 } 上述三個變數,在編譯時,是由編譯器規劃其空間,最後是放在 stack 裡面, 而這類型的變數有個特性:在程式執行的時候(稱執行期),這些變數可能會改變。 這是我猜測書本對於「動態」之解釋。 補註,這麼解釋真的不盡人意,因完全忽略了 static variable - static int a=10; 這才是真正的 static variable, 還有一類型的變數,他們在執行的時候並不會改變他們的內含值 (value), 如 const variable ,像是這段 code { const char* txt="hello, world!!"; const double PI=3.1415926; } 在程式執行txt 和 PI 從頭到尾都不可能會被改變(又是一個錯誤的思考:靜態), 它們不是被放在 stack 裡面,遺憾的也不是放在 heap 裡, 而是被放在其它的記憶體區段裡,這區段就叫 .rodata 區段,都是放唯讀的資料。 ( 這也是那本書沒提到的部份 ) 上面這段的重點只是:變數不宣告成 const 的話,是放在 stack , (雖這句話一點點問題..),完畢。 ----- : 但是又在動態記憶體章節上面寫說C++都是預設靜態什麼的 很讓人搞混 我猜書本上指的動態記憶體,大多指的是動態陣列 (雖然有時不一定要是陣列..) 截至目前為止,上敘其實只有提到 auto variable 是放在 stack 裡面。 接下來所有講「動態記憶體」,指的全部都是用 new / malloc 指令的東西, 但我很怕你會愈來愈亂,所以這部份重頭簡述至尾。 後半段必須探討到指標的東西,不熟的話再去複習一次。 一般而言,如果是寫 int arr[5] = {1,2,3,4,5}; 這種方式宣告陣列的話,因為大小一開始就固定,在程式的 編譯期 就可以算出要多大, 且在 執行期 不可以改變陣列的大小,屬於靜態陣列。 ( 還記得上一段有提到嗎?靜態陣列是放在 stack 裡面。) 但有時候,陣列要給多大必須在執行期的時候才可以知道, 比如說,先輸入班上有幾個人,再輸入每個人的成績,再做平均。 這時候沒辦法在 編譯期 時候就知道人數,此時會使用動態配置。 (如果扣掉被大多數人所垢病的 可變長度陣列,VLA, 作法時,只剩動態配置一途) 另,希望你沒忘記一件事:即使是指標,本身存的是「記憶體位址」, 故你常看到的動態配置的東西 { int *a = NULL; a = new int[10]; for(int i=0; i<10; ++i) a[i] = i; } 注意的是, a 本身是指標,它是在 編譯期 裡面就決定的東西, 是放在 stack 裡面。 而 a = new int[10]new int[10] 一開始先在 heap 上配置 10 個 int 大小, 最後把這 heap 的 "第一個位址值" 再傳回來給 a, 意思是如果配置的空間是 0x90000000 0x90000004 ..... 最後 a 會存的是 0x90000000。 但這並不改變, a 本身是在 stack 上的事實, 會在 heap 上操作,只有這些動作: *a=1 、 *(a+1)=10 、 a[1] = 10 因為是籍由指標 a ,去操作剛剛在 heap 上 new (這動作叫 allocate) 出來的記憶體。 所以呢? int a[3]={1,2,3}; // 靜態記憶體陣列,放在 stack int *a = new int[3]; // a 本身是指標,放在 stack; // 而 a[i] 或 *(a+i) 本身放在 heap。 那放在 stack 和 heap 上有什麼差別? 速度 (access speed) 應是一樣的, 有幾個地方是顯然不同。 (a) 要用 heap 必須調用 new / malloc 相關指令 (在不考慮使用低階 api 情況下) (b) 靜態陣列、一般變數 (扣除 const、static、global,但含 pointer), 是放在 stack 裡面,這在 編譯期 就可以由編譯器規劃好的東西; 而 heap 在編譯時要多大不知道,是在 執行期 時才由作業系統幫忙規劃。 (c) stack 可使用的空間範圍較小,而 heap 可使用的空間範圍較大; 所以,若陣列的元素個數很多,即使元素個數是固定的,也必須在 heap 上使用, 而不能放在 stack 裡面。意指:去試試 double x[2000000]; 好一點的 compiler 可能會有警告還是錯誤,這時候必須用 int *x=new int[2000000]; : ok 總之我目前的認知是一般的陣列是靜態宣告... : (以下都是區域變數) : int a; 跟 auto int a; 等價,而且這是動態 : int a[5]; 是靜態,,,應該吧? 這裡不要記動態、靜態,書本要表達的意思是, int a; ---> 它是放在 stack 裡面 (用 動態 來形容就差了) int a[5]; ---> 它是靜態的記憶體,因為不是用 new 運算子配置出來的, 也是放在 stack 裡面。 : 那假設我宣告如下(當然是區域): : auto int a[5]; 這到底該算靜態還是動態? 已經試過編譯可以過... 完整的說法是: 因為它是 local auto variable,而不是 const variable (唯讀變數), 它的值可以被改變,放在 stack 裡面。 而陣列的大小固定為 5 ,在編譯期就可以知道的大小,是靜態陣列 也由於它不是唯讀,也是放在 stack 裡面。 : 如果是靜態那不是表示auto關鍵字在這裡沒用嗎@@? : 如果是動態的話那跟 : int* a; a = new int[5];又有何不同 這點上面有說過了,細閱。 (結語 : 我可以說為什麼我不推這本書的原因了嗎? XD) -- 世界上有種, 不可能 轉換為 無限可能 的強大力量, 我稱它為 - 信念 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 180.177.69.239
tinlans:auto 之所以叫 auto,是因為不用手動控制它的生死。 01/19 19:47
tinlans:中文書用的詞彙,在講解這東西時很容易造成混亂是真的。 01/19 19:48
james732:推用心講解XD 01/19 21:12
angleevil:我只能說t大全部講解完了,實際上local variable預設 01/19 21:20
angleevil:是auto變數. 01/19 21:22
yudsx:推解釋詳細 只能說作者這樣寫很容易讓初學者誤會 01/19 22:45
LifePattern:第一次聽到用auto來說,就說是local會alloca在stack不 01/19 22:53
LifePattern:就OK了.. 01/19 22:53
tropical72:但 local 不一定會 allocate 在 stack 下啊 ~ 01/19 22:57
tropical72:好吧,或許我不該特別挑這問題出來講 XD 01/19 22:59
chunhsiang:可以問您 DLL載入的東西,他們的記憶體位置又會在哪裡? 01/19 23:44
chunhsiang:是OS幫忙載入,所以是在OS的另外的記憶體區段中? 01/19 23:46
amozartea:謝謝,請推薦我有寫這方面部份的書... 01/19 23:51
tropical72:dll問題扯太遠了,另開主題佳. 書:程式設計師的自我修養 01/19 23:52
amozartea:我讀過的都是語法和資料結構書等等都沒有講這方面QQ 01/19 23:53
diabloevagto:長知識! 01/20 00:01
LifePattern:我也推:程式設計師的自我修養! 01/20 00:56
LifePattern:local不會allocate在stack是指static var還是被優化? 01/20 01:00
tropical72:@LifePattern : static variable. const variable. 01/20 01:02
LifePattern:謝了,忘了const XD 01/20 01:19
LoveCheer:t大文 只有推了 01/20 07:07
s3748679:推用心+1 01/20 17:25
FOXSMALL:有學到!推一個 02/03 17:45