C語言----函數棧幀講解

目錄

1.函數棧幀是什么?

2. 理解函數棧幀能解決什么問題?

3、函數棧幀的創建和銷毀具體過程

3.1 什么是棧

3.2 認識相關寄存器和匯編指令

3.3函數棧幀的創建和銷毀

3.3.1 預備知識

3.3.2 函數的調用堆棧

3.3.3?準備環境

3.3.4 轉到反匯編

3.3.5 函數棧幀的創建

3.3.6 函數棧幀的銷毀

相關概念知識(輔助理解):

1.棧(Stack)

2.?esp?和?ebp?的作用

3. 寄存器

1.通用寄存器(General-Purpose Registers)

2. 段寄存器(Segment Registers)

3. 控制寄存器(Control Registers)

4. 關鍵寄存器詳解:


1.函數棧幀是什么?

在C語言中書寫代碼時, 我們通常會把一個獨立的功能用函數來實現, 不同的函數用來實現不同的功能,? 所以C程序是以函數為基本單位的。? 那函數是如何被調用的?? 函數的返回值又是如何待會的????????函數的形參和實參是如何傳遞的?? 這些問題都和函數棧幀有關系。

函數棧幀(Stack Frame)?是函數運行時在內存棧(Stack)中占用的一個獨立空間,用來存儲該函數運行所需的所有臨時數據。

獨立空間所存放的數據包括:

函數參數和函數返回的地址(函數返回值)

舊的基指針(保存調用者(Caller)的棧幀基址(EBP/RBP))

局部變量和臨時數據

2. 理解函數棧幀能解決什么問題?

只要理解了函數棧幀的創建和銷毀,就能大概弄懂一下的問題

  • 局部變量是如何創建的?
  • 為什么局部變量不初始化內容是隨機的?
  • 函數調用時參數時如何傳遞的?傳參的順序是怎樣的?
  • 函數的形參和實參分別是怎樣實例化的?
  • 函數的返回值是如何帶會的?

3、函數棧幀的創建和銷毀具體過程

3.1 什么是棧

棧(Stack)是現代計算機程序的核心基礎之一,幾乎所有程序都依賴它運行。

簡單來說,棧就像一個嚴格遵守"后來先出"規則的容器:數據像疊盤子一樣被壓入(push)棧頂,取出時也只能從最上面彈出(pop)。

在計算機中,棧是一塊特殊的內存區域,由CPU通過棧指針寄存器(如x86架構的ESP/RSP)自動管理,隨著數據壓入棧頂指針向低地址移動(棧向下增長),彈出時則向高地址回退。

正是這個精巧的設計,使得函數調用、局部變量存儲、參數傳遞等關鍵功能得以實現,可以說沒有棧就沒有現代編程語言中的函數概念。

3.2 認識相關寄存器和匯編指令

相關寄存器:

1.eax:通用寄存器,保留臨時數據,常用于返回值

2.ebx:通用寄存器,保留臨時數據

3.ebp:棧底寄存器

4.esp:棧頂寄存器

5.eip:指令寄存器,保存當前指令的下一條指令的地址

匯編指令:

1.call:保存下一條指令地址(返回地址)到棧頂,并跳轉到目標函數

2.ret:從棧頂彈出返回地址,跳轉回調用位置繼續執行。? ? ?

3.push:將數據壓入棧頂,棧指針下移(棧向低地址增長)。?

4.pop:從棧頂彈出數據,棧指針上移。

5.enter:建立新棧幀(保存舊幀指針,分配局部變量空間)。?

6.leave:撤銷當前棧幀(恢復舊幀指針和棧指針)。? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

7.mov (ebp/esp):直接操作幀指針(ebp)或棧指針(esp),用于調整棧結構。

8.sub/add (esp):動態調整棧空間(如分配/釋放局部變量)。

3.3函數棧幀的創建和銷毀

3.3.1 預備知識

首先我們達成一些預備知識才能有效的幫助我們理解,函數棧幀的創建和銷毀。

1.每一次函數調用,都要為本次函數調用開辟空間,就是函數棧幀的空間。

2.這塊空間的維護是使用了2個寄存器: esp 和 ebp , ebp 記錄的是棧底的地址, esp 記錄的是棧頂的地址。? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

3.?函數棧幀的創建和銷毀過程,在不同的編譯器上實現的方法大同小異。

如圖:

3.3.2 函數的調用堆棧

演示代碼:

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
int Mystrlen(char* arr)
{if (*arr != '\0')return	1+Mystrlen(arr+1);elsereturn 0;
}
int main()
{char arr1[10] = "abcdedg";int len = Mystrlen(arr1);printf("%d", len);return 0;
}

這段代碼,如果我們在VS2022編譯器上調試,調試進入Mystrlen函數后,我們就可以觀察到函數的調用堆棧(右擊勾選【顯示外部代碼】)如下圖:

打開方法:

通過菜單欄打開: 啟動調試(按?F5?或點擊?調試 >)

開始調試在調試狀態下,點擊菜單欄的?調試 (Debug)選擇?窗口 (Windows) > 調用堆棧 (Call Stack)。

快捷鍵:Ctrl + Alt + C(默認)。

函數調用堆棧是反饋函數調用邏輯的,那我們可以清晰的觀察到, main 函數調用之前,是由 invoke_main 函數來調用main函數。在 invoke_main 函數之前的函數調用我們就暫時不考慮了。那我們可以確定, invoke_main 函數應該會有自己的棧幀, main 函數和 Add 函數也會維護自己的棧幀,每個函數棧幀都有自己的 ebp 和 esp 來維護棧幀空間。那接下來我們從main函數的棧幀創建開始講解:

3.3.3?準備環境

為了讓我們研究函數棧幀的過程足夠清晰,不要太多干擾,我們可以關閉下面的選項,讓匯編代碼中排除一些編譯器附加的代碼:

3.3.4 轉到反匯編

調試到main函數開始執行的第一行,右擊鼠標轉到反匯編。
注:VS編譯器每次調試都會為程序重新分配內存,課件中的反匯編代碼是一次調試代碼過程中數據,每次調試略有差異。

int main()
{
//函數棧幀的創建
00007FF79DB71900  push        rbp  
00007FF79DB71902  push        rdi  
00007FF79DB71903  sub         rsp,148h  
00007FF79DB7190A  lea         rbp,[rsp+20h]  
00007FF79DB7190F  lea         rdi,[rsp+20h]  
00007FF79DB71914  mov         ecx,2Ah  
00007FF79DB71919  mov         eax,0CCCCCCCCh  
00007FF79DB7191E  rep stos    dword ptr [rdi]  
00007FF79DB71920  mov         rax,qword ptr [__security_cookie (07FF79DB7D000h)]  
00007FF79DB71927  xor         rax,rbp  
00007FF79DB7192A  mov         qword ptr [rbp+118h],rax  
00007FF79DB71931  lea         rcx,[__167BB7BA_源@c (07FF79DB82008h)]  
00007FF79DB71938  call        __CheckForDebuggerJustMyCode (07FF79DB71370h)  
00007FF79DB7193D  nop  
//main函數中的核心代碼char arr1[10] = "abcdedg";
00007FF79DB7193E  mov         rax,qword ptr [string "abcdedg" (07FF79DB7AC70h)]  
00007FF79DB71945  mov         qword ptr [arr1],rax  
00007FF79DB71949  lea         rax,[rbp+60h]  
00007FF79DB7194D  mov         rdi,rax  
00007FF79DB71950  xor         eax,eax  
00007FF79DB71952  mov         ecx,2  
00007FF79DB71957  rep stos    byte ptr [rdi]  int len = Mystrlen(arr1);
00007FF79DB71959  lea         rcx,[arr1]  
00007FF79DB7195D  call        Mystrlen (07FF79DB713DEh)  
00007FF79DB71962  mov         dword ptr [len],eax  printf("%d", len);
00007FF79DB71968  mov         edx,dword ptr [len]  
00007FF79DB7196E  lea         rcx,[string "%d" (07FF79DB7ACB4h)]  
00007FF79DB71975  call        printf (07FF79DB7119Ah)  
00007FF79DB7197A  nop  return 0;
00007FF79DB7197B  xor         eax,eax  
}
3.3.5 函數棧幀的創建

這里我看到 main 函數轉化來的匯編代碼如上所示。接下來我們就一行行拆解匯編代碼:

00007FF79DB71900  push        rbp  
//將調用者(如invoke_main)的棧基址rbp壓棧保存,esp自動-8(x64下指針占8字節)
//此時rsp指向棧頂,保存了舊的rbp值00007FF79DB71902  push        rdi  
//保存rdi寄存器的值到棧中(x64調用約定中rdi可能被調用者修改),esp再-800007FF79DB71903  sub         rsp,148h  
//給main函數分配棧空間:rsp減去0x148字節(328字節)
//現在rsp指向main函數棧幀的頂部,與后續的rbp構成棧幀范圍00007FF79DB7190A  lea         rbp,[rsp+20h]  
//設置main函數的棧基址rbp = rsp + 0x20
//這樣rbp到rsp之間保留0x20字節(可能用于調試或局部變量)00007FF79DB7190F  lea         rdi,[rsp+20h]  
//將rdi指向棧初始化區域的起始地址(rbp的位置),準備填充0xCC00007FF79DB71914  mov         ecx,2Ah  
//設置循環次數ecx = 0x2A(42次),每次處理4字節,共初始化42*4=168字節00007FF79DB71919  mov         eax,0CCCCCCCCh  
//用調試模式填充值0xCCCCCCCC初始化棧空間(未初始化內存的標記)00007FF79DB7191E  rep stos    dword ptr [rdi]  
//從rdi指向的地址開始,重復填充eax的值(0xCCCCCCCC)到內存,共ecx次
//相當于初始化[rbp-0x20]到[rbp+0xA8]的范圍(168字節)00007FF79DB71920  mov         rax,qword ptr [__security_cookie (07FF79DB7D000h)]  
// 從全局變量加載安全cookie(棧溢出保護值)到rax00007FF79DB71927  xor         rax,rbp  
//將安全cookie與當前棧基址rbp異或,生成唯一校驗值00007FF79DB7192A  mov         qword ptr [rbp+118h],rax  
//將校驗值存入棧中[rbp+0x118]的位置(函數返回時會驗證是否被篡改)00007FF79DB71931  lea         rcx,[__167BB7BA_源@c (07FF79DB82008h)]  
//加載調試信息符號地址到rcx(用于"Just My Code"調試功能)00007FF79DB71938  call        __CheckForDebuggerJustMyCode (07FF79DB71370h)  
//調用VS調試器檢查函數,確認是否在調試模式下運行00007FF79DB7193D  nop  
//空指令(用于對齊或預留調試斷點位置)

上面的這段代碼,等價于下面的偽代碼:

void main() {// 1. 保存調用者的棧基址和寄存器push(rbp);          // 保存invoke_main的rbppush(rdi);          // 保存可能被修改的rdi// 2. 分配棧空間(x64下更大)rsp -= 0x148;       // 分配328字節空間// 3. 設置新的棧基址(跳過預留區域)rbp = rsp + 0x20;   // rbp指向有效棧幀起始處// 4. 初始化棧空間(填充0xCC)rdi = rbp;          // 初始化起始地址ecx = 42;           // 循環次數(42次×4字節=168字節)eax = 0xCCCCCCCC;memset(rdi, eax, ecx * 4); // 填充168字節// 5. 棧溢出保護(x64特有)rax = __security_cookie;      // 加載安全cookierax ^= rbp;                   // 與棧基址異或加密*(rbp + 0x118) = rax;         // 存儲校驗值// 6. 調試檢查(VS特有)if (IsDebuggerPresent()) {    // 檢查調試器__CheckForDebuggerJustMyCode(); // 調試鉤子}
}

小知識 : 燙燙燙燙燙燙燙燙燙燙燙燙

出現 “燙燙燙……” 的原因是:在 Windows 下,未初始化的棧內存可能會被初始化為 0xCC ,而 0xCC 對應的字符在當前字符編碼下顯示為 “燙” 。

接下來我們再分析main函數中的核心代碼:

1. 初始化字符數組?arr1[10] = "abcdedg";

00007FF79DB7193E  mov         rax, qword ptr [string "abcdedg" (07FF79DB7AC70h)]  
//從全局數據段(地址 `07FF79DB7AC70h`)加載字符串 `"abcdedg"` 的前 8 字節到 `rax`。
//由于 `"abcdedg"` 是 7 字節(含 `\0`),rax 會包含'a','b','c','d','e','d','g','\0'00007FF79DB71945  mov         qword ptr [arr1], rax  
//將 `rax` 的值(即字符串的前 8 字節)存儲到 `arr1` 的起始地址(`[arr1]`)。
//此時 `arr1` 的前 8 字節已填充為 `"abcdedg\0"`。00007FF79DB71949  lea         rax, [rbp+60h]  
//計算 `arr1` 的剩余部分地址(`rbp+60h`)
//即 `arr1[8]` 的位置(因為 `arr1` 是 `char[10]`,前 8 字節已填充,剩余 2 字節)。00007FF79DB7194D  mov         rdi, rax  
//將目標地址 `rbp+60h` 存入 `rdi`(`stos` 指令的目的寄存器)。00007FF79DB71950  xor         eax, eax  
//清零 `eax`,即 `al = 0`(`\0` 字符)。00007FF79DB71952  mov         ecx, 2  
//設置循環次數 `ecx = 2`(剩余 2 字節需要填充 `\0`)。00007FF79DB71957  rep stos    byte ptr [rdi]  
//從 `rdi` 指向的地址開始,重復填充 `al`(`0`)到內存,共 `ecx` 次(2 次)。
//相當于 `arr1[8] = '\0'; arr1[9] = '\0';`,確保數組完全以 `\0` 結尾。

2. 調用?Mystrlen(arr1)?計算字符串長度

00007FF79DB71959  lea         rcx, [arr1]  
//將 `arr1` 的地址加載到 `rcx`(x64 調用約定:第一個參數用 `rcx` 傳遞)。00007FF79DB7195D  call        Mystrlen (07FF79DB713DEh)  
//調用 `Mystrlen` 函數,返回值存儲在 `eax` 中。00007FF79DB71962  mov         dword ptr [len], eax  
//將返回值(字符串長度)存入局部變量 `len`。

3. 調用?printf?打印長度

00007FF79DB71968  mov         edx, dword ptr [len]  
//將 `len` 的值(`7`)存入 `edx`(x64 調用約定:第二個參數用 `edx` 傳遞)。00007FF79DB7196E  lea         rcx, [string "%d" (07FF79DB7ACB4h)]  
//加載格式字符串 `"%d"` 的地址到 `rcx`(第一個參數)。00007FF79DB71975  call        printf (07FF79DB7119Ah)  
//調用 `printf`,輸出 `7`。00007FF79DB7197A  nop  
//空指令(對齊或占位)。

4. 返回?0

00007FF79DB7197B  xor         eax, eax  
//將 `eax` 清零(`return 0;` 的常見優化寫法)。
3.3.6 函數棧幀的銷毀

當函數調用要結束返回的時候,前面創建的函數棧幀也開始銷毀。那具體是怎么銷毀的呢?我們看一下反匯編代碼。

00007FF773182288  lea     rsp, [rbp+0C8h]  
//將 rsp 直接設置為 rbp + 0C8h,相當于回收整個函數的棧空間(esp = ebp + 分配的大小)  
//此時 rsp 指向調用者棧幀的棧頂(函數調用前的 rsp 值)  00007FF77318228F  pop     rdi  
//從棧頂彈出一個值,存放到 rdi 中(恢復調用者的 rdi 寄存器),rsp + 8(x64 下指針占 8 字節)  00007FF773182290  pop     rbp  
//從棧頂彈出一個值,存放到 rbp 中,此時棧頂的值就是調用者的 rbp(恢復調用者的棧基址),rsp + 8  00007FF773182291  ret  
//ret 指令的執行:  
//1. 從棧頂彈出一個值(此時棧頂的值就是 call 指令下一條指令的地址),rsp + 8  
//2. 跳轉到該地址,繼續執行調用者的代碼  

這樣之后就會跳轉到main函數內繼續執行代碼

本章結束 以上就是函數棧幀創建和銷毀

以下是一些概念知識 需要的可自行閱讀


相關概念知識(輔助理解):

1.棧(Stack)

棧是一種后進先出(LIFO)的數據結構,在內存中從高地址向低地址增長。在函數調用時,棧用于:

  • 存儲函數參數(由調用者壓棧)
  • 保存返回地址(call指令自動壓入)
  • 保存調用者的ebp(被調函數保存)
  • 分配局部變量
  • 存儲臨時數據(如運算中間結果)

2.?esp?和?ebp?的作用

寄存器全稱作用
espExtended Stack Pointer始終指向棧的當前頂部(最低可用地址),隨push/pop動態變化
ebpExtended Base Pointer指向當前函數棧幀的基地址,用于定位局部變量和參數

esp?的特點

  • 動態變化,每次pushpopsub esp, N(分配空間)或add esp, N(釋放空間)都會改變。
  • 在函數調用時,esp會調整以容納新的棧幀。

ebp?的特點

  • 在函數執行期間固定,作為局部變量和參數的基準。
  • 通過[ebp + offset]訪問參數,[ebp - offset]訪問局部變量。

3. 寄存器

寄存器(Registers)是CPU內部的高速存儲單元,用于臨時存放數據、地址和控制信息。在函數調用和棧幀管理中,關鍵的寄存器包括?通用寄存器段寄存器?和?控制寄存器

1.通用寄存器(General-Purpose Registers)

這些寄存器可用于計算、尋址和數據傳輸,主要分為:

寄存器名稱主要用途
eaxAccumulator存放函數返回值、算術運算
ebxBase數據存儲(較少用于計算)
ecxCounter循環計數(如rep指令)
edxData輔助eax(如乘法/除法的高位結果)
esiSource Index字符串/數組操作的源指針
ediDestination Index字符串/數組操作的目標指針
espStack Pointer指向棧頂(動態變化)
ebpBase Pointer指向當前棧幀基址(固定)
2. 段寄存器(Segment Registers)

用于內存分段(現代操作系統已較少使用):

寄存器名稱用途
csCode Segment代碼段基址
dsData Segment數據段基址
ssStack Segment棧段基址(esp/ebp默認在此段)
es,?fs,?gsExtra Segments附加數據段
3. 控制寄存器(Control Registers)
寄存器名稱用途
eipInstruction Pointer指向下一條要執行的指令(不可直接修改)
eflagsFlags存儲狀態標志(如零標志ZF、進位標志CF
4. 關鍵寄存器詳解:

(1)esp(Stack Pointer)

  • 作用:始終指向棧的當前頂部(即最后入棧的數據地址)。
  • 變化規則
    • push?時:esp?減小(棧向低地址增長)。
    • pop?時:esp?增大
    • 函數調用時,esp?會動態調整以分配/釋放棧空間。

(2)ebp(Base Pointer)

  • 作用:指向當前函數棧幀的基地址,用于:
    • 定位局部變量([ebp - offset])。
    • 訪問函數參數([ebp + offset])。
  • 特點
    • 在函數執行期間固定不變(除非手動修改)。
    • 通過?mov ebp, esp?在函數開頭建立棧幀。

本博客借鑒于:函數棧幀的創建與銷毀(超詳解)-CSDN博客

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/902968.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/902968.shtml
英文地址,請注明出處:http://en.pswp.cn/news/902968.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

代碼隨想錄學習筆記---二叉樹

學習目標&#xff1a; 學習代碼隨想錄–二叉樹 每天學習1道,復習兩道 學習內容&#xff1a; 2025.4.7 復習內容: 24. 兩兩交換鏈表中的節點 25. 最大二叉樹 學習內容 26. 合并二叉樹 2025.4.8 復習內容: 27. 二分查找 28. 合并二叉樹 29. 27. 移除元素 學習內容: 30. 二叉…

Git ——提交至github,Vercel拉取,更新不了項目的問題解決

首先因為github上有個錯誤 1 failing check Vercel - No GitHub account was found matching the commit author email address 發現好像是vercel拉取不了項目&#xff0c;vercel登錄的郵箱與我此次提交更改的郵箱不匹配&#xff0c;查看Git的user確實如此&#xff08;之前的…

Vue3項目中 npm 依賴安裝 --save 與 --save-dev 的區別解析

這兩個命令的區別如下&#xff1a; bash npm install --save types/crypto-js # 安裝到 dependencies&#xff08;生產依賴&#xff09; npm install --save-dev types/crypto-js # 安裝到 devDependencies&#xff08;開發依賴&#xff09; 核心區別 依賴分類不同…

品牌如何通過朝日新聞出海日本?——某企業日本媒體發稿實戰

文 | 言同數字亞太傳播實驗室 一、日本市場的隱形門檻&#xff1a;中國品牌的三大痛點 案例背景&#xff1a; 某中國靈芝保健品企業&#xff08;代號"ForestLife"&#xff09;&#xff0c;產品雖獲中國/歐盟有機認證&#xff0c;但在日本市場面臨&#xff1a; 認知…

鴻蒙-試一下屬性字符串:除了Span之外,如何在同一個Text組件中展示不同樣式的文字

文章目錄 前言簡介有哪些類型拉出來溜溜Text SpanStyledString其他CustomSpan先看一下構造函數onMeasure(measureInfo: CustomSpanMeasureInfo): CustomSpanMetricsonDraw(context: DrawContext, drawInfo: CustomSpanDrawInfo) 遺留問題 前言 在開發中&#xff0c;經常會遇到…

Nginx 安裝與配置全流程指南(2025 最新版)

一、環境準備與依賴安裝 1.1 系統要求 操作系統&#xff1a;支持主流 Linux 發行版&#xff08;Ubuntu 20.04/CentOS 7/Debian 10&#xff09;硬件配置&#xff1a;內存 ≥512MB&#xff0c;磁盤 ≥10GB 可用空間&#xff08;建議使用 SSD&#xff09;網絡要求&#xff1a;開…

【LeetCode 熱題 100】滑動窗口最大值 / 最小覆蓋子串 / 輪轉數組 / 缺失的第一個正數

??個人主頁&#xff1a;小羊 ??所屬專欄&#xff1a;LeetCode 熱題 100 很榮幸您能閱讀我的文章&#xff0c;誠請評論指點&#xff0c;歡迎歡迎 ~ 目錄 子串和為 K 的子數組滑動窗口最大值最小覆蓋子串 普通數組最大子數組和合并區間輪轉數組除自身以外數組的乘積缺失的…

golang的cgo的一點小心得

最后有個項目需要涉及到cgo&#xff0c;在這塊以前用的不多&#xff0c; 這次略微用得深入了一點&#xff0c;記下來幾點以備以后使用 本質上cgo去用的時候就是遵守一些ABI而已&#xff0c;總體而言&#xff0c;盡量避免復雜結構的來回傳遞。1 對于變長參數&#xff0c;只有…

異構網絡環境下的切換策略研究

移動互聯網應用快速崛起,現有的無線接入技術有,無線局域網(Wireless Local Area NetWork,WLAN),移動蜂窩網絡(4G,5G),無線廣域網(Wireless Wide Area Network,WWAL)以及衛星通信網絡等。多接入技術方便用戶通信,還符合多業務場景。這種多無線接入技術共存的網絡環…

人工智能賦能美妝零售數字化轉型:基于開源AI大模型的S2B2C商城系統構建

摘要 在消費升級背景下&#xff0c;美妝行業正經歷從傳統賣場向智能體驗空間的轉型。本文以"未來商店"為研究對象&#xff0c;探討開源AI大模型與S2B2C商城系統的協同效應&#xff0c;揭示人工智能技術如何重構"人-貨-場"關系。通過實證研究發現&#xff…

計算機視覺中的正則化:從理論到實踐的全面解析

&#x1f31f; 計算機視覺中的正則化&#xff1a;從理論到實踐的全面解析&#x1f31f; 大家好&#xff01;今天要和大家分享的是在計算機視覺&#xff08;CV&#xff09;領域中非常重要的一個概念——正則化&#xff08;Regularization&#xff09;。無論你是剛開始接觸深度學…

Linux字符設備驅動開發的詳細步驟

1. 確定主設備號?? ??手動指定??&#xff1a;明確設備號時&#xff0c;使用register_chrdev_region()靜態申請&#xff08;需確保未被占用&#xff09;。??動態分配??&#xff1a;通過alloc_chrdev_region()由內核自動分配主設備號&#xff08;更靈活&#xff0c;推…

軟件工程效率優化:一個分層解耦與熵減驅動的系統框架

軟件工程效率優化&#xff1a;一個分層解耦與熵減驅動的系統框架** 摘要 (Abstract) 本報告構建了一個全面、深入、分層的軟件工程效率優化框架&#xff0c;旨在超越簡單的技術羅列&#xff0c;從根本的價值驅動和熵減原理出發&#xff0c;系統性地探討提升效率的策略與實踐。…

【Docker游戲】使用Docker部署vue-XiuXianGame文字修仙小游戲

【Docker游戲】使用Docker部署vue-XiuXianGame文字修仙小游戲 一、vue-XiuXianGame介紹1.1 vue-XiuXianGame簡介1.2 主要特點 二、本次實踐規劃2.1 本地環境規劃2.2 本次實踐介紹 三、本地環境檢查3.1 檢查Docker服務狀態3.2 檢查Docker版本3.3 檢查docker compose 版本 四、拉…

用 LangChain 手搓 RAG 系統:從原理到實戰

一、RAG 系統簡介 在當今信息爆炸的時代&#xff0c;如何高效地從海量數據中獲取有價值的信息并生成準確、自然的回答&#xff0c;成為了人工智能領域的重要課題。檢索增強生成&#xff08;Retrieval-Augmented Generation&#xff0c;RAG&#xff09;系統應運而生&#xff0c;…

SpringBoot集成LiteFlow實現輕量級工作流引擎

LiteFlow 是一款專注于邏輯驅動流程編排的輕量級框架&#xff0c;它以組件化方式快速構建和執行業務流程&#xff0c;有效解耦復雜業務邏輯。通過支持熱加載規則配置&#xff0c;開發者能夠即時調整流程步驟&#xff0c;將復雜的業務如價格計算、下單流程等拆分為獨立且可復用的…

38 python random

在實際中,我們常常會用到隨機的概念,比如 模擬抽獎活動(如:月度優秀員工抽獎)生成測試數據(如:隨機考勤時間、隨機銷售額)打亂數據順序(如:隨機分配任務到人)Python 的random模塊就像你的 "隨機事件生成器",幫你輕松創建各種隨機數據 一、基礎操作:從隨…

附贈二張圖,闡述我對大模型的生態發展、技術架構認識。

文章精煉&#xff0c;用兩張圖說明大模型發展業態方向&#xff0c;以及大模型主體技術架構。&#xff08;目前還需要進一步驗證我的Thought && ideas&#xff0c;等待機會吧.........&#xff09; 圖一&#xff1a;探究大模型三個層次應用方向&#xff0c;淺層次入門簡…

2025上海車展 | 移遠通信全棧車載智能解決方案重磅亮相,重構“全域智能”出行新范式

2025年4月23日至5月2日&#xff0c;第二十一屆上海國際汽車工業展覽會在國家會展中心&#xff08;上海&#xff09;盛大啟幕。作為車載智能解決方案領域的領軍企業&#xff0c;移遠通信以“全域智能 馭見未來”為主題&#xff0c;攜豐富的車載解決方案及客戶終端驚艷亮相8.2館8…

告別 “幻覺” 回答:RAG 中知識庫與生成模型的 7 種對齊策略

一、引言 大語言模型&#xff08;LLM&#xff09;在文本生成領域展現出驚人能力&#xff0c;但 “幻覺” 問題&#xff08;生成虛構或偏離事實的內容&#xff09;始終是落地應用的核心挑戰。檢索增強生成&#xff08;RAG&#xff09;通過將外部知識庫與 LLM 結合&#xff0c;形…