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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

c++内存分布

發(fā)布時(shí)間:2024/9/30 c/c++ 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++内存分布 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
作者:吳秦

出處:http://www.cnblogs.com/skynet/


為什么需要知道C/C++的內(nèi)存布局和在哪可以可以找到想要的數(shù)據(jù)?知道內(nèi)存布局對(duì)調(diào)試程序非常有幫助,可以知道程序執(zhí)行時(shí),到底做了什么,有助于寫出干凈的代碼。本文的主要內(nèi)容如下:

  • 源文件轉(zhuǎn)換為可執(zhí)行文件
  • 可執(zhí)行程序組成及內(nèi)存布局
  • 數(shù)據(jù)存儲(chǔ)類別
  • 一個(gè)實(shí)例
  • 總結(jié)

源文件轉(zhuǎn)換為可執(zhí)行文件

源文件經(jīng)過以下幾步生成可執(zhí)行文件:

  • 1、預(yù)處理(preprocessor):對(duì)#include、#define、#ifdef/#endif、#ifndef/#endif等進(jìn)行處理
  • 2、編譯(compiler):將源碼編譯為匯編代碼
  • 3、匯編(assembler):將匯編代碼匯編為目標(biāo)代碼
  • 4、鏈接(linker):將目標(biāo)代碼鏈接為可執(zhí)行文件

編譯器和匯編器創(chuàng)建的目標(biāo)文件包含:二進(jìn)制代碼(指令)、源碼中的數(shù)據(jù);鏈接器將多個(gè)目標(biāo)文件鏈接成一個(gè);裝載器吧目標(biāo)文件加載到內(nèi)存。

圖1 源文件到可執(zhí)行文件的步驟

?

可執(zhí)行程序組成及內(nèi)存布局

通過上面的小節(jié),我們知道將源程序轉(zhuǎn)換為可執(zhí)行程序的步驟,典型的可執(zhí)行文件分為兩部分:

  • 代碼段(Code),由機(jī)器指令組成,該部分是不可改的,編譯之后就不再改變,放置在文本段(.text)。
  • 數(shù)據(jù)段(Data),它由以下幾部分組:
    • 常量(constant),通常放置在只讀read-only的文本段(.text
    • 靜態(tài)數(shù)據(jù)(static data),初始化的放置在數(shù)據(jù)段(.data);未初始化的放置在(.bss,Block Started by Symbol,BSS段的變量只有名稱和大小卻沒有值)
    • 動(dòng)態(tài)數(shù)據(jù)(dynamic data),這些數(shù)據(jù)存儲(chǔ)在堆(heap)或棧(stack

源程序編譯后鏈接到一個(gè)以0地址為始地址的線性或多維虛擬地址空間。而且每個(gè)進(jìn)程都擁有這樣一個(gè)空間,每個(gè)指令和數(shù)據(jù)都在這個(gè)虛擬地址空間擁有確定的地址,把這個(gè)地址稱為虛擬地址(Virtual Address)。將進(jìn)程中的目標(biāo)代碼、數(shù)據(jù)等的虛擬地址組成的虛擬空間稱為虛擬存儲(chǔ)器(Virtual Memory)。典型的虛擬存儲(chǔ)器中有類似的布局:

  • Text Segment (.text)
  • Initialized Data Segment (.data)
  • Uninitialized Data Segment (.bss)
  • The Stack
  • The Heap

如下圖所示:

圖2 進(jìn)程內(nèi)存布局

當(dāng)進(jìn)程被創(chuàng)建時(shí),內(nèi)核為其提供一塊物理內(nèi)存,將虛擬內(nèi)存映射到物理內(nèi)存,這些都是由操作系統(tǒng)來做的。

數(shù)據(jù)存儲(chǔ)類別

討論C/C++中的內(nèi)存布局,不得不提的是數(shù)據(jù)的存儲(chǔ)類別!數(shù)據(jù)在內(nèi)存中的位置取決于它的存儲(chǔ)類別。一個(gè)對(duì)象是內(nèi)存的一個(gè)位置,解析這個(gè)對(duì)象依賴于兩個(gè)屬性:存儲(chǔ)類別、數(shù)據(jù)類型。

  • 存儲(chǔ)類別決定對(duì)象在內(nèi)存中的生命周期。
  • 數(shù)據(jù)類型決定對(duì)象值的意義,在內(nèi)存中占多大空間。

C/C++中由(auto、 extern、 register、 static)存儲(chǔ)類別和對(duì)象聲明的上下文決定它的存儲(chǔ)類別。

1、自動(dòng)對(duì)象(automatic objects)

autoregister將聲明的對(duì)象指定為自動(dòng)存儲(chǔ)類別。他們的作用域是局部的,諸如一個(gè)函數(shù)內(nèi),一個(gè)代碼塊{***}內(nèi)等。操作了作用域,對(duì)象會(huì)被銷毀。

  • 在一個(gè)代碼塊中聲明一個(gè)對(duì)象,如果沒有執(zhí)行auto,那么默認(rèn)是自動(dòng)存儲(chǔ)類別。
  • 聲明為register的對(duì)象是自動(dòng)存儲(chǔ)類別,存儲(chǔ)在計(jì)算機(jī)的快速寄存器中。不可以對(duì)register對(duì)象做取值操作“&”。

2、靜態(tài)對(duì)象(static objects)

靜態(tài)對(duì)象可以局部的,也可以是全局的。靜態(tài)對(duì)象一直保持它的值,例如進(jìn)入一個(gè)函數(shù),函數(shù)中的靜態(tài)對(duì)象仍保持上次調(diào)用時(shí)的值。包含靜態(tài)對(duì)象的函數(shù)不是線程安全的、不可重入的,正是因?yàn)樗哂小坝洃洝惫δ堋?/p>

  • 局部對(duì)象聲明為靜態(tài)之后,將改變它在內(nèi)存中保存的位置,由動(dòng)態(tài)數(shù)據(jù)--->靜態(tài)數(shù)據(jù),即從堆或棧變?yōu)閿?shù)據(jù)段或bbs段。
  • 全局對(duì)象聲明為靜態(tài)之后,而不會(huì)改變它在內(nèi)存中保存的位置,仍然是在數(shù)據(jù)段或bbs段。但是static將改變它的作用域,即該對(duì)象僅在本源文件有效。此相反的關(guān)鍵字是extern,使用extern修飾或者什么都不帶的全局對(duì)象的作用域是整個(gè)程序。

?

一個(gè)實(shí)例

下面我們分析一段代碼:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <stdio.h> #include <stdlib.h> int a; static int b; void func( void ) { ????char c; ????static int d; } int main( void ) { ????int e; ????int *pi = ( int *) malloc ( sizeof ( int )); ????func (); ????func (); ????free (pi ); ????return (0); }

程序中聲明的變量a、b、c、d、e、pi的存儲(chǔ)類別和生命期如下所述:

  • a是一個(gè)未初始化的全局變量,作用域?yàn)檎麄€(gè)程序,生命期是整個(gè)程序運(yùn)行期間,在內(nèi)存的bbs段
  • b是一個(gè)未初始化的靜態(tài)全局變量,作用域?yàn)楸驹次募?#xff0c;生命期是整個(gè)程序運(yùn)行期間,在內(nèi)存的bbs段
  • c是一個(gè)未初始化的局部變量,作用域?yàn)楹瘮?shù)func體內(nèi),即僅在函數(shù)體內(nèi)可見,生命期也是函數(shù)體內(nèi),在內(nèi)存的棧中
  • d是一個(gè)未初始化的靜態(tài)局部變量,作用域?yàn)楹瘮?shù)func體內(nèi),即僅在函數(shù)體內(nèi)可見,生命期是整個(gè)程序運(yùn)行期間,在內(nèi)存的bbs段
  • e是一個(gè)未初始化的局部變量,作用域?yàn)楹瘮?shù)main體內(nèi),即僅在函數(shù)體內(nèi)可見,生命期是main函數(shù)內(nèi),在內(nèi)存的棧中
  • pi是一個(gè)局部指針,指向堆中的一塊內(nèi)存塊,該塊的大小為sizeof(int),pi本身存儲(chǔ)在內(nèi)存的棧中,生命期是main函數(shù)內(nèi)
  • 新申請(qǐng)的內(nèi)存塊在堆中,生命期是malloc/free之間

用圖表示如下:

圖3 例子的內(nèi)存布局

?

總結(jié)

本文介紹了C/C++中由源程序到可執(zhí)行文件的步驟,和可執(zhí)行程序的內(nèi)存布局,數(shù)據(jù)存儲(chǔ)類別,最后還通過一個(gè)例子來說明。可執(zhí)行程序中的變量在內(nèi)存中的布局可以總結(jié)為如下:

  • 變量(函數(shù)外):如果未初始化,則存放在BSS段;否則存放在data段
  • 變量(函數(shù)內(nèi)):如果沒有指定static修飾符,則存放在棧中;否則同上
  • 常量:存放在文本段.text
  • 函數(shù)參數(shù):存放在棧或寄存器中

內(nèi)存可以分為以下幾段:

  • 文本段:包含實(shí)際要執(zhí)行的代碼(機(jī)器指令)和常量。它通常是共享的,多個(gè)實(shí)例之間共享文本段。文本段是不可修改的。
  • 初始化數(shù)據(jù)段:包含程序已經(jīng)初始化的全局變量,.data。
  • 未初始化數(shù)據(jù)段:包含程序未初始化的全局變量,.bbs。該段中的變量在執(zhí)行之前初始化為0或NULL。
  • 棧:由系統(tǒng)管理,由高地址向低地址擴(kuò)展。
  • 堆:動(dòng)態(tài)內(nèi)存,由用戶管理。通過malloc/alloc/realloc、new/new[]申請(qǐng)空間,通過free、delete/delete[]釋放所申請(qǐng)的空間。由低地址想高地址擴(kuò)展。

總結(jié)

以上是生活随笔為你收集整理的c++内存分布的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。