C語言 記憶體佈局

来源:https://www.cnblogs.com/eezhijun/archive/2023/10/18/17695854.html
-Advertisement-
Play Games

GCC編譯 預處理->編譯->彙編->鏈接 預處理:頭⽂件包含、巨集替換、條件編譯、刪除註釋... 編譯:主要進⾏詞法、語法、語義分析等,檢查⽆誤後將預處理好的⽂件編譯成彙編⽂件... 彙編:將彙編⽂件轉換成 ⼆進位⽬標⽂件... 鏈接:將項⽬中的各個⼆進位⽂件+所需的庫+啟動代碼鏈接成可執⾏⽂件.. ...


GCC編譯

預處理->編譯->彙編->鏈接

預處理:頭⽂件包含、巨集替換、條件編譯、刪除註釋...
編譯:主要進⾏詞法、語法、語義分析等,檢查⽆誤後將預處理好的⽂件編譯成彙編⽂件...
彙編:將彙編⽂件轉換成 ⼆進位⽬標⽂件...
鏈接:將項⽬中的各個⼆進位⽂件+所需的庫+啟動代碼鏈接成可執⾏⽂件...

記憶體佈局

當我們運行程式時,可載入到 RAM 中。如下是一個記憶體佈局圖。
image

示例代碼

#include <stdio.h>
#include <stdlib.h>

#include "utils.h"

/* memory layout test */
/* #define STR(s) #s */
static int u_s_g_var_a; /* 未初始化靜態全局變數a 存放在bss段 */
static int i_s_g_var_b = 10; /* 已初始化靜態全局變數b 存在在data段 */

static int *u_s_g_var_p;
static int *i_s_g_val_p = &u_s_g_var_a;

int u_g_var_c; /* 未初始化全局變數c */
int i_g_var_d = 10; /* 已初始化全局變數d */

const int u_g_c_var_e; /* const 修飾未初始化全局常量 */
const int i_g_c_var_f = 10; /* const 修飾初始化全局常量 */

void func_test(void)
{
    printf("func\n");
}

int test_memory_layout(void)
{
    int l_var_a;
    int l_var_b = 10;
    int *l_var_c = NULL;
    int *l_var_d = NULL;
    static int u_s_l_var_e;
    static int i_s_l_var_f = 10;
    const int u_l_c_var_g;
    const int i_l_c_var_h = 10;
    char *l_var_s = "Hello World";
    char l_var_arr[] = "Hello World";
    const int *l_p_a =  &l_var_a;   /* 常量指針 */
    int * const l_p_b = &l_var_b;       /* 指針常量 */
    const int * const l_p_c =  &i_l_c_var_h;    /* 指向常量的常指針 */
    int *l_var_aa = (int *)alloca(sizeof(int) * 4); /* 從棧分配記憶體 */
		static int *i_s_l_var_p = &u_g_var_c;

    printf("-----------------------------------------------------\n");
    printf("棧區\n");
    printf("%s\t\t%p\n", STR(l_var_aa), l_var_aa);
    printf("%s\t\t\t%p\n", STR(l_var_a), &l_var_a);
    printf("%s\t\t\t%p\n", STR(l_var_b), &l_var_b);
    printf("%s\t\t%p\n", STR(&l_var_c), &l_var_c);
    printf("%s\t\t%p\n", STR(&l_var_d), &l_var_d);
    printf("%s\t\t%p\n", STR(u_l_c_var_g), &u_l_c_var_g);
    printf("%s\t\t%p\n", STR(i_l_c_var_h), &i_l_c_var_h);
    printf("%s\t\t%p\n", STR(&l_var_s), &l_var_s);
    printf("%s\t\t\t%p\n", STR(&l_p_a), &l_p_a);
    printf("%s\t\t\t%p\n", STR(&l_p_b), &l_p_b);
    printf("%s\t\t\t%p\n", STR(&l_p_c), &l_p_c);
    printf("%s\t\t%p\n", STR(l_var_arr), l_var_arr);


    l_var_c = (int *)malloc(sizeof(int) * 4);
    l_var_d = (int *)malloc(sizeof(int) * 4);
    printf("-----------------------------------------------------\n");
    printf("堆區\n");
    printf("%s\t\t\t%p\n", STR(l_var_c), l_var_c);
    printf("%s\t\t\t%p\n", STR(l_var_d), l_var_d);

    printf("-----------------------------------------------------\n");
    printf("bss區\n");
    printf("%s\t\t%p\n", STR(u_s_g_var_a), &u_s_g_var_a);
    printf("%s\t\t%p\n", STR(u_g_var_c), &u_g_var_c);
    printf("%s\t\t%p\n", STR(u_s_l_var_e), &u_s_l_var_e);
    printf("%s\t\t%p\n", STR(u_g_c_var_e), &u_g_c_var_e);
    printf("%s\t\t%p\n", STR(&i_s_l_var_p), &i_s_l_var_p);
    printf("%s\t\t%p\n", STR(&u_s_g_var_p), &u_s_g_var_p);
    printf("%s\t\t%p\n", STR(&i_s_g_val_p), &i_s_g_val_p);

    printf("-----------------------------------------------------\n");
    printf("data區\n");
    printf("%s\t\t%p\n", STR(i_s_g_var_b), &i_s_g_var_b);
    printf("%s\t\t%p\n", STR(i_g_var_d), &i_g_var_d);
    printf("%s\t\t%p\n", STR(i_s_l_var_f), &i_s_l_var_f);

    printf("-----------------------------------------------------\n");
    printf("text區\n");
    printf("常量\n");
    printf("%s\t\t%p\n", STR(i_g_c_var_f), &i_g_c_var_f);
    printf("%s\t\t\t%p\n", STR(l_var_s), l_var_s);

    printf("代碼\n");
    printf("%s\t%p\n", STR(memory_layout_test), memory_layout_test);
    printf("%s\t\t%p\n", STR(func_test), func_test);

    free(l_var_c);
    l_var_c = NULL;
    free(l_var_d);
    l_var_d = NULL;
    return 0;
}

void main_test(void)
{
    printf("TEST ENTRY\n");
    printf("GNU libc version: %s\n", gnu_get_libc_version());
    memory_layout_test();
}

運行結果:

-----------------------------------------------------
棧區
l_var_aa                0xffcc5760
l_var_a                 0xffcc5784
l_var_b                 0xffcc5788
&l_var_c                0xffcc578c
&l_var_d                0xffcc5790
u_l_c_var_g             0xffcc5794
i_l_c_var_h             0xffcc5798
&l_var_s                0xffcc579c
&l_p_a                  0xffcc57a0
&l_p_b                  0xffcc57a4
&l_p_c                  0xffcc57a8
l_var_arr               0xffcc57b0
-----------------------------------------------------
堆區
l_var_c                 0x57f895b0
l_var_d                 0x57f895d0
-----------------------------------------------------
bss區
u_s_g_var_a             0x565d0050
u_g_var_c               0x565d004c
u_s_l_var_e             0x565d0058
u_g_c_var_e             0x565cca08
i_s_l_var_p             0x565d004c
&i_s_l_var_p            0x565d001c
&u_s_g_var_p            0x565d0054
&i_s_g_val_p            0x565d0018
-----------------------------------------------------
data區
i_s_g_var_b             0x565d000c
i_g_var_d               0x565d0010
i_s_l_var_f             0x565d0014
-----------------------------------------------------
text區
常量
i_g_c_var_f             0x565cca0c
l_var_s                 0x565cca15
代碼
test_memory_layout      0x565c9b5e
func_test               0x565c9b33
參考鏈接:

https://en.wikipedia.org/wiki/Data_segment

https://en.wikipedia.org/wiki/Memory_segmentation

https://medium.com/@vikasv210/memory-layout-in-c-fe4dffdaeed6

https://github.com/gatieme/AderXCoding/tree/master/language/c/memory_layout


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • mybatis逆向工程,即利用現有的數據表結構,生成對應的model實體類、dao層介面,以及對應的mapper.xml映射文件。藉助mybatis逆向工程,我們無需手動去創建這些文件。 下麵是使用Java代碼的方式來實現逆向工程,生成文件(也可以使用插件來生成): 首先,導入需要的依賴包:myba ...
  • 正文 上一篇文章講解了獲取事務,並且通過獲取的connection設置只讀、隔離級別等,這篇文章講解剩下的事務的回滾和提交。最全面的Java面試網站 回滾處理 之前已經完成了目標方法運行前的事務準備工作,而這些準備工作最大的目的無非是對於程式沒有按照我們期待的那樣進行,也就是出現特定的錯誤,那麼,當 ...
  • 在之前的代碼中我們並沒有對套接字進行加密,在未加密狀態下我們所有的通信內容都是明文傳輸的,這種方式在學習時可以使用但在真正的開發環境中必須要對數據包進行加密,此處筆者將演示一種基於時間的加密方法,該加密方法的優勢是數據包每次發送均不一致,但數據包內的內容是一致的,當抓包後會發現每次傳輸的數據包密文是... ...
  • 題目:從前有一隻青蛙他想跳臺階,有n級臺階,青蛙一次可以跳1級臺階,也可以跳2級臺階;問:該青蛙跳到第n級臺階一共有多少種跳法。 當只有跳一級臺階的方法跳時,總共跳n步,共有1次跳法 當用了一次跳二級臺階的方法跳時,總共跳n-1步,共有n-1次跳法 當用了兩次跳二級臺階的方法跳時,總共跳n-2步,共 ...
  • 安裝 miniconda 1、下載安裝包 Miniconda3-py37_22.11.1-1-Linux-x86_64.sh,或者自行選擇版本 2、把安裝包上傳到伺服器上,這裡放在 /home/software 3、安裝 bash Miniconda3-py37_22.11.1-1-Linux-x8 ...
  • 1.使用 for key in dict 遍歷字典 可以使用 for key in dict 遍歷字典中所有的鍵 x = {'a': 'A', 'b': 'B'} for key in x: print(key) # 輸出結果 a b 2.使用 for key in dict.keys () 遍歷字 ...
  • 在 Python 編程中,異常是一種常見的情況,可能會導致程式中斷或產生錯誤。然而,並非所有的異常都需要立即處理,有時候我們希望忽略某些異常並繼續執行程式。本文將介紹如何在 Python 中忽略異常,並提供一些示例和註意事項。 try-except 塊: 在 Python 中,我們可以使用 try- ...
  • 前言 ElasticSearch Java API是ES官方在8.x版本推出的新java api,也可以適用於7.17.x版本的es。 本文主要參考了相關博文,自己手動編寫了下相關操作代碼,包括更新mappings等操作的java代碼。 代碼示例已上傳github。 版本 elasticsearch ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...