日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C.2#【数据段】—2.数据段data、bss、rodata

發布時間:2024/3/24 编程问答 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C.2#【数据段】—2.数据段data、bss、rodata 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.1 data 段

用來存儲已經初始化的全局變量,也屬于靜態內存分配區,會占用程序文件空間。

與bss相比,data就容易明白多了,它的名字就暗示著里面存放著數據。當然,如果數據全是零,為了優化考慮,編譯器把它當作bss處理。通俗的說,data指那些初始化過(非零)的非const的全局變量。它有什么特點呢,我們還是來看看一個小程序的表現。
int data_array[1024 * 1024] = {1};

int main(int argc, char* argv[])
{
? ? return 0;
}

[root@localhost data]# gcc -g data.c -o data.exe
[root@localhost data]# ll
total 4112
-rw-r--r-- 1 root root? ?? ?85 Jun 22 14:35 data.c
-rwxr-xr-x 1 root root 4200025 Jun 22 14:35 data.exe

僅僅是把初始化的值改為非零了,文件就變為4M多。由此可見,data類型的全局變量是即占文件空間,又占用運行時內存空間的。

1.2 bss 段

BSS(Block Started by Symbol)用來存儲未初始化的全局變量和靜態變量,全局變量或靜態變量值為0或NULL(對于指針變量而言)的通常會被編譯器認為未初始化,屬于靜態內存分配區,不會占用程序文件空間,不存儲這些變量在外存上,但是還是會占用一部分空間,這些空間用來標識未初始化的變量大小、屬性等信息.

BSS段(bsssegment)通常是指用來存放程序中未初始化的全局變量的一塊內存區域。

并不給該段的數據分配空間,只是記錄數據所需要的空間大小。

它有什么特點呢,讓我們來看看一個小程序的表現。
int bss_array[1024 * 1024] = {0};

int main(int argc, char* argv[])
{
? ? return 0;
}
[root@localhost bss]# gcc -g bss.c -o bss.exe
[root@localhost bss]# ll
total 12
-rw-r--r-- 1 root root? ?84 Jun 22 14:32 bss.c
-rwxr-xr-x 1 root root 5683 Jun 22 14:32 bss.exe

變量bss_array的大小為4M,而可執行文件的大小只有5K。?由此可見,bss類型的全局變量只占運行時的內存空間,而不占文件空間。

另外,大多數操作系統,在加載程序時,會把所有的bss全局變量全部清零,無需要你手工去清零。但為保證程序的可移植性,手工把這些變量初始化為0也是一個好習慣。

1.3 rodata?

rodata的意義同樣明顯,ro代表read only,即只讀數據(const)。

關于rodata類型的數據,要注意以下幾點:

  • 常量不一定就放在rodata里,有的立即數直接編碼在指令里,存放在代碼段(.text)中。
  • 對于字符串常量,編譯器會自動去掉重復的字符串,保證一個字符串在一個可執行文件(EXE/SO)中只存在一份拷貝。
  • rodata是在多個進程間是共享的,這可以提高空間利用率。
  • 在有的嵌入式系統中,rodata放在ROM(如norflash)里,運行時直接讀取ROM內存,無需要加載到RAM內存中。
  • 在嵌入式linux系統中,通過一種叫作XIP(就地執行)的技術,也可以直接讀取,而無需要加載到RAM內存中。

?由此可見,把在運行過程中不會改變的數據設為rodata類型的,是有很多好處的:在多個進程間共享,可以大大提高空間利用率,甚至不占用RAM空間。同時由于rodata在只讀的內存頁面(page)中,是受保護的,任何試圖對它的修改都會被及時發現,這可以幫助提高程序的穩定性。

text段:

代碼段(codesegment/textsegment)通常是指用來存放程序執行代碼的一塊內存區域。這部分區域的大小在程序運行前就已經確定,并且內存區域通常屬于只讀,某些架構也允許代碼段為可寫,即允許修改程序。在代碼段中,也有可能包含一些只讀的常數變量,例如字符串常量等。

heap堆:

堆是用于存放進程運行中被動態分配的內存段,它的大小并不固定,可動態擴張或縮減。當進程調用malloc等函數分配內存時,新分配的內存就被動態添加到堆上(堆被擴張);當利用free等函數釋放內存時,被釋放的內存從堆中被剔除(堆被縮減)

stack棧:

是用戶存放程序臨時創建的局部變量,也就是說我們函數括弧“{}”中定義的變量(但不包括static聲明的變量,static意味著在數據段中存放變量)。除此以外,在函數被調用時,其參數也會被壓入發起調用的進程棧中,并且待到調用結束后,函數的返回值也會被存放回棧中。由于棧的先進先出特點,所以棧特別方便用來保存/恢復調用現場。從這個意義上講,我們可以把堆棧看成一個寄存、交換臨時數據的內存區。

常量段:

常量段一般包含編譯器產生的數據(與只讀段包含用戶定義的只讀數據不同)。比如說由一個語句a=2+3編譯器把2+3編譯期就算出5,存成常量5在常量段中

1.8.變量與關鍵字

static關鍵字

用途太多,以致于讓新手模糊。不過,總結起來就有兩種作用,改變生命期限制作用域。如:
l? ?? ?? ?修飾inline函數:限制作用域
l? ?? ?? ?修飾普通函數:限制作用域
l? ?? ?? ?修飾局部變量:改變生命期
l? ?? ?? ?修飾全局變量:限制作用域

靜態局部變量屬于靜態儲存類別,在靜態儲存區內分配儲存單元。在整個程序運行期間都不釋放



const 關鍵字

倒是比較明了,用const修飾的變量放在rodata里,字符串默認就是常量。對const,注意以下幾點就行了。
l? ?? ????指針常量:指向的數據是常量。如?const?char* p =?“abc”;?p指向的內容是常量 ,但p本身不是常量,你可以讓p再指向”123”。
l? ?? ?? ?常量指針:指針本身是常量。如:char*?const?p?= “abc”; p本身就是常量,你不能讓p再指向”123”。
l? ?? ?? ?指針常量 + 常量指針:指針和指針指向的數據都是常量。const char* const p =”abc”; 兩者都是常量,不能再修改。

violatile關鍵字

通常用來修飾多線程共享的全局變量和IO內存。告訴編譯器,不要把此類變量優化到寄存器中,每次都要老老實實的從內存中讀取,因為它們隨時都可能變化。這個關鍵字可能比較生僻,但千萬不要忘了它,否則一個錯誤讓你調試好幾天也得不到一點線索。

問題1,二進制文件不包含BSS段,那把BSS段放在哪?
答:修改有1000個全局變量,難道要BIN里要存1000個0嗎?在鏈接腳本里把BSS段組織在一起,記下它的起始地址、結束地址,重定位后把這塊內存清0即可

問題2:全局變量不初始化的話默認初始化為零,干嘛還要手動清零?
答:因為它是在BSS段的

總結

以上是生活随笔為你收集整理的C.2#【数据段】—2.数据段data、bss、rodata的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。