const全域性變數位於哪個段

2021-06-20 08:14:44 字數 1417 閱讀 3250

方法:

1、設計若干個const全域性變數的例子,用g++編譯生成可執行檔案(例如a.out)

2、用readelf -s a.out 檢視elf檔案各段的資訊

3、用objdump -s a.out檢視main函式反彙編,確定呼叫的位址

4、根據呼叫的位址和2中查單到的段資訊,確定呼叫的位址位於哪個段

5、也可繞過3、4步,直接用readelf -s a.out檢視符號表,從中得知特定符號位於哪個段

情況1:

const int aaa = 0xf0f0f0f0;

int main()

結論:符號表中根本就不存在aaa這個符號。應該是在編譯階段就把aaa全部替換成為0xf0f0f0f0。在本例中是乙個int常量,所以用objdump可以直接在彙編指令中看到0xf0f0f0f0體現為立即數。

情況2:

extern const int aaa;

int main()

結論:extern的作用,我的理解是,告訴編譯器,aaa這個符號還有可能在別的檔案中用到。所以從這個層面上來說,aaa放到data段或者rodata段才能體現這一特性。既然是const,那麼就是放在rodata段才對。用readelf -s a.out檢視符號aaa的位址和它所在的段號,再結合readelf -s a.out的結果,驗證了這一猜測。

情況3:

上面兩種const全域性變數都是用所謂的」常量表示式「初始化。還有一種不是用常量表示式初始化的情況:

int fun()

const int aaa = fun();

int main()

用readelf -x .rodata a.out 和readelf -x .data a.out檢視rodata和data段,沒有看到0xf0f0f0f0。再用readelf -s a.out看符號表,會看到乙個_zl3aaa的符號,起始位址是08049694,bind屬性是local,位於編號為25的段內。編號為25的段正是bss段。再檢視main函式的彙編,能看到對應語句位置引用的位址也是0849694。

所以,這種情況下的const全域性變數是放在bss段內的。

發散:有一種方法可以修改const的值:

int * ptr = const_cast(&r);//c++標準,c語言使用:int * ptr =(int*)&r;

* ptr = 0xf1f1f1f1;//修改

但是這種方法不是通用的。能成功修改的前提是r這個const變數必須位於可讀可寫的段內。假如r位於rodata段,就如上文的情況2,可以編譯通過,但執行的時候會報段錯誤,因為rodata段的屬性是唯讀的。而情況3就能正常執行,因為bss段可讀可寫。

const 和全域性變數

c 中,全域性變數的儲存都是靜態儲存。但是鏈結性質可以有外部鏈結和內部鏈結。預設情況下是外部鏈結,如果在定義前加上 static 則變為內部鏈結。如果 int val1 5 加上static 則編譯失敗。但是如果是用const 呢。變成 const int val1 5 會如何呢,答案是,也編譯失敗...

C 靜態變數 全域性變數 const

全域性陣列 不能被delete 作用域 區分名字的不同意義的上下文。c 中大多數作用域是用花括號界定的,名字從其宣告點到宣告所在作用域結束處都是可見的。include int main int sum 0 for int val 1 val 10 val sum return 1 名字main在花括...

static全域性變數 全域性變數

1 全域性變數 外部變數 的說明之前再冠以static 就構成了靜態的全域性變數。全域性變數本身就是靜態儲存方式,靜態全域性變數當然也是靜態儲存方式。這兩者在儲存方式上並無不同。這兩者的區別在於非靜態全域性變數的作用域是整個源程式,當乙個源程式由多個原始檔組成時,非靜態的全域性變數在各個原始檔中都是...