C語言中奇技淫巧08-使用alloca/__builtin_alloca從棧上分配空間

  1. alloca是什么?
    alloca 是一個非標準但廣泛支持的 C 語言函數,用于在當前函數的棧(stack)上動態分配內存。
  • 與 malloc 的區別:
    • malloc 在堆(heap) 上分配內存,需要手動調用 free 釋放。
    • alloca 在棧上分配內存,函數返回時會自動釋放,無需手動 free。
  • 優點:分配和釋放速度快(棧操作很快),內存自動管理。
  • 缺點:
    • 分配的內存大小受限于棧空間(通常比堆小得多),分配過大可能導致棧溢出(stack overflow)。
    • 不是 C 標準的一部分,可移植性較差。
    • 在循環中使用可能導致棧持續增長(雖然函數返回會釋放,但循環內反復調用仍可能有問題)。
  1. __builtin_alloca 是什么?
    __builtin_ 開頭的函數是 GCC(GNU Compiler Collection)等編譯器提供的“內置函數”(built-in functions)。
  • __builtin_alloca 是 GCC 對 alloca 功能的編譯器級實現。
  • 它不是鏈接時從庫中加載的普通函數,而是在編譯階段由編譯器直接生成相應的匯編代碼(通常是調整棧指針 esp/rsp)。
  • 這使得它比調用一個普通的庫函數 alloca 更高效,也更底層。
  1. 示例
#include <stdio.h>// 假設這個宏已經被定義(在某些系統頭文件中常見)
// #define alloca(size) __builtin_alloca(size)void example(int n) {// 在棧上分配 n 個 int 的空間int *arr = (int*)alloca(n * sizeof(int));// 使用分配的內存for (int i = 0; i < n; i++) {arr[i] = i * i;}printf("arr[5] = %d\n", arr[5]); // 假設 n > 5// 函數返回時,arr 所指向的棧內存自動釋放// 無需 free(arr)
}int main() {example(10);return 0;
}

在這個例子中,alloca(n * sizeof(int)) 會被預處理器替換為 __builtin_alloca(n * sizeof(int)),然后編譯器直接生成調整棧指針的指令來完成內存分配。

  1. 重要注意事項
  • 不要在非葉函數(non-leaf function)中使用 alloca:如果函數 A 調用了 alloca,然后又調用了其他函數 B,B 的棧幀可能會覆蓋 A 中 alloca 分配的區域,導致未定義行為。
  • 避免在循環中使用:雖然安全,但可能導致棧空間持續增長。
  • 檢查返回值:alloca 和 __builtin_alloca 在分配失敗(如棧溢出)時不會返回 NULL,而是導致程序崩潰。因此無法像 malloc 那樣檢查錯誤。
  • 可移植性問題:盡管廣泛支持,但在某些編譯器或系統上可能不可用。更現代、更安全的替代方案是使用 變長數組(VLA, Variable Length Array)(C99 標準支持,但 C11 不強制要求),例如:
void func(int n) {int arr[n]; // C99 VLA,在棧上分配// ...
} // arr 自動釋放
  1. Linux ManualPage中是這樣描述的
//在棧上分配內存,并在函數返回時自動釋放
#include <alloca.h>void *alloca(size_t size);
  • 分配位置: 在調用者的棧幀(stack frame)中分配內存。

這意味著 alloca 分配的內存屬于調用它的那個函數的棧空間。

  • 自動釋放: 當調用 alloca 的函數返回時,這塊內存會自動被回收(通過棧指針的移動)。
  • 返回值:
    • 成功時:返回指向分配內存的指針。
    • 失敗時(棧溢出):未定義行為(undefined behavior)。

這是 alloca 最大的風險之一。它不會返回 NULL 來指示失敗。如果分配的內存過大,導致棧溢出,程序很可能直接崩潰(如段錯誤),且無法在代碼中安全地檢測和處理這種錯誤。

  • 屬性:
    • MT-Safe 表示該函數是線程安全的(Multi-Thread Safe)。
    • 原因:每個線程都有自己的棧,alloca 在當前線程的棧上分配內存,不會與其他線程的棧發生沖突。因此,多個線程同時調用 alloca 是安全的。
  • STANDARDS (標準)
    None.
    • 這是最關鍵的一點:alloca 不屬于任何正式的 C 語言標準(如 ISO C90, C99, C11, C17)。
    • 它是一個非標準擴展,其存在和行為依賴于具體的編譯器和操作系統實現。
    • 這意味著使用 alloca 的代碼可移植性較差,在某些編譯器或平臺上可能不可用。
  • NOTES (注意事項)
    • alloca() 函數的實現依賴于具體的機器架構和編譯器。因為它是在棧上進行分配,所以它比 malloc(3) 和 free(3) 更快。在某些情況下,對于使用 longjmp(3) 或 siglongjmp(3) 的應用程序,它也可以簡化內存釋放。除此之外,不鼓勵使用 alloca()。
    • 由于 alloca() 分配的空間位于棧幀內,如果通過調用 longjmp(3) 或 siglongjmp(3) 跳過了函數的返回過程,那么這部分空間也會被自動釋放。
    • 如果指向 alloca() 分配空間的指針只是簡單地超出了其作用域(例如,在嵌套代碼塊中定義的指針),那么該空間不會被自動釋放。
    • 切勿嘗試使用 free(3) 來釋放 alloca() 分配的空間!
    • 由于實現上的需要,alloca() 本質上是一個編譯器內置函數(built-in),也被稱為 __builtin_alloca()。現代編譯器默認會自動將所有對 alloca() 的調用轉換為該內置函數。但是,如果請求了標準符合性(如使用 -ansi 或 -std=c* 編譯選項),這種自動轉換是被禁止的,此時必須包含 <alloca.h> 頭文件,否則會產生一個符號依賴。
    • alloca() 是一個內置函數這一事實意味著:無法獲取它的地址,也無法通過鏈接不同的庫來改變它的行為。
    • 變長數組(Variable Length Arrays, VLAs) 是 C99 標準的一部分,自 C11 標準起變為可選特性,可以用于類似的目的。然而,它們無法移植到標準 C++ 中,并且作為變量,它們存在于其代碼塊的作用域內,沒有類似內存分配器的接口,因此不適合用于實現 strdupa(3) 這樣的功能。
  • BUGS (缺陷)
    • 由于棧的特性,無法檢查分配操作是否會超出棧的可用空間,因此也無法指示錯誤。(不過,如果程序試圖訪問不可用的空間,很可能會收到一個 SIGSEGV 信號。)
    • 在許多系統上,不能在函數調用的參數列表中使用 alloca(),因為 alloca() 在棧上保留的空間會出現在函數參數所用空間的中間位置。

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

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

相關文章

【Markdown轉Word完整教程】從原理到實現

Markdown轉Word完整教程&#xff1a;從原理到實現 前言 在技術文檔編寫和學術論文創作中&#xff0c;Markdown因其簡潔的語法和良好的可讀性而廣受歡迎。然而&#xff0c;在實際工作中&#xff0c;我們經常需要將Markdown文檔轉換為Word格式&#xff0c;以便與同事協作、提交正…

IBM穿孔卡片:現代計算技術的奠基之作

本文由「大千AI助手」原創發布&#xff0c;專注用真話講AI&#xff0c;回歸技術本質。拒絕神話或妖魔化。搜索「大千AI助手」關注我&#xff0c;一起撕掉過度包裝&#xff0c;學習真實的AI技術&#xff01; 1 打孔卡概述 穿孔卡片&#xff08;Punch Card&#xff09;又稱打孔卡…

亞馬遜旺季來臨如何用woot沖刺

在亞馬遜旺季來臨之際&#xff0c;使用Woot沖刺需結合新品推廣、老品激活、庫存清理等不同場景&#xff0c;通過精準選品、活動設置、廣告配合及數據監控實現銷量與排名的雙重提升。以下是具體操作指南&#xff1a;一、精準選品&#xff1a;匹配提報條件新品期選品標準&#xf…

AlexNet:計算機視覺的革命性之作

AlexNet: Revolutionizing Deep Learning for Computer Vision (1)網絡提出的背景 論文題目:ImageNet Classification with Deep Convolutional Neural Networks arXiv地址:https://arxiv.org/abs/1207.0575 在2012年ImageNet大規模視覺識別挑戰賽(ILSVRC)中,AlexNet以15…

【高等數學】第十一章 曲線積分與曲面積分——第二節 對坐標的曲線積分

上一節&#xff1a;【高等數學】第十一章 曲線積分與曲面積分——第一節 對弧長的曲線積分 總目錄&#xff1a;【高等數學】 目錄 文章目錄1. 對坐標的曲線積分的概念與性質1. 對坐標的曲線積分的概念與性質 變力沿曲線所作的功 先用曲線 LLL 上的點 M1(x1,y1),M2(x2,y2),…,M…

解析SQL Server核心服務與功能

SQL Server 安裝后會在 Windows 系統中注冊多個服務&#xff0c;每種服務負責不同的功能。主要服務類型包括&#xff1a; &#x1f4cc; 核心服務 (必須或常用)SQL Server Database Engine (數據庫引擎服務) 服務名稱格式&#xff1a; MSSQL$<InstanceName> (命名實例) 或…

專項智能練習(計算機動畫基礎)

1.小明在制作Flash作品時&#xff0c;舞臺及庫中素材如第下圖所示&#xff0c;把“馬”元件插入到“馬”圖層第1幀并放在舞臺的草地位置&#xff0c;發現舞臺中并無馬圖像顯示&#xff0c;下列情形中最有可能的是&#xff08; &#xff09;。A.“馬”圖層已被鎖定 B.“馬”圖層…

第三方庫集成:結合 Express.js 構建本地服務器

引言&#xff1a;Express.js 在 Electron 第三方庫集成中的本地服務器構建價值 在 Electron 框架的第三方庫集成生態中&#xff0c;Express.js 作為 Node.js 的經典 Web 框架&#xff0c;扮演著構建本地服務器的關鍵角色。它不僅僅是一個路由和中間件工具&#xff0c;更是 Elec…

百度地圖+vue+flask+爬蟲 推薦算法旅游大數據可視化系統Echarts mysql數據庫 帶沙箱支付+圖像識別技術

F012 百度地圖vueflask爬蟲 推薦算法旅游大數據可視化系統Echarts mysql數據庫 帶沙箱支付圖像識別技術 &#x1f4da;編號&#xff1a; F012 文章結尾部分有CSDN官方提供的學長 聯系方式名片 博主開發經驗15年,全棧工程師&#xff0c;專業搞定大模型、知識圖譜、算法和可視化…

# 開發中使用——鴻蒙CoreSpeechKit讓文字發聲后續

開發中使用——鴻蒙CoreSpeechKit讓文字發聲后續 設置音量大小 volume// 設置播報相關參數this.extraParam {"queueMode": 0, "speed": AppModel.speed, "volume": AppModel.volume, "pitch": 1, "languageContext": zh-CN,…

Java全棧開發面試實錄:從基礎到微服務的深度探索

Java全棧開發面試實錄&#xff1a;從基礎到微服務的深度探索 面試官與應聘者的初次見面 面試官&#xff1a;你好&#xff0c;很高興見到你。請先做個自我介紹吧。 應聘者&#xff1a;您好&#xff0c;我叫李明&#xff0c;今年28歲&#xff0c;是南京大學計算機科學與技術專業的…

前端路由切換不再白屏:React/Vue 實戰優化全攻略(含可運行 Demo)

摘要 在單頁應用&#xff08;SPA&#xff09;開發中&#xff0c;React、Vue、Angular 這些主流框架都依賴前端路由來完成頁面切換。好處是顯而易見的&#xff1a;首屏資源一次加載&#xff0c;后續頁面切換靠前端路由完成&#xff0c;體驗比傳統的多頁應用要順暢很多。 但是在實…

C#之LINQ

文章目錄前言LINQ一、LINQ1一、LINQ2一、LINQ3Where方法&#xff1a;每一項數據都會進過predicate的測試&#xff0c;如果針對一個元素&#xff0c;predicate執行的返回值為true&#xff0c;那么這個元素就會放到返回值中。獲取一條數據&#xff08;是否帶參數的兩種寫法&#…

第 2 講:Kafka Topic 與 Partition 基礎

課程概述 在第一篇課程中&#xff0c;我們了解了 Kafka 的基本概念和簡單的 Producer/Consumer 實現。 本篇課程將深入探討 Kafka 的核心機制&#xff1a;Topic 和 Partition。 學習目標 通過本課程&#xff0c;您將掌握&#xff1a; Topic 和 Partition 的設計原理&#x…

三階Bezier曲線曲率極值及對應的u的計算方法

三階&#xff08;三次&#xff09;Bezier曲線的曲率極值及其對應的參數 u 的計算是一個復雜的非線性優化問題。由于三階Bezier曲線是參數化曲線&#xff0c;其曲率表達式較為復雜&#xff0c;通常無法通過解析方法直接求得所有極值點&#xff0c;但可以通過求解曲率導數為零的方…

Unity:XML筆記(二)——Xml序列化、反序列化、IXmlSerializable接口

寫在前面&#xff1a;寫本系列(自用)的目的是回顧已經學過的知識、記錄新學習的知識或是記錄心得理解&#xff0c;方便自己以后快速復習&#xff0c;減少遺忘。三、Xml序列化序列化就是把想要存儲的內容轉換為字節序列用于存儲或傳遞。1、序列化我們先創建一個類&#xff0c;之…

java注解、Lambda表達式、Servlet

一、Java注解注解的概念&#xff1a; Java注解是代碼中的元數據&#xff0c;可以用于描述其他代碼。注解在編譯、類加載、運行時被處理&#xff0c;并且不會改變代碼邏輯。注解的用途&#xff1a; 提供代碼元信息&#xff0c;如 Override 表明一個方法覆蓋了父類的方法。 編譯檢…

【單片機day02】

GPIO&#xff1a;Genral Purpose Input/Output&#xff0c;GPIO是51單片機和外界交互最基本的方式工作模式&#xff1a;輸出模式&#xff1a;單片機給定引腳一個電平(高電平(5V) 低電平(0V)),控制引腳實現高低電平輸入模式&#xff1a;檢測引腳電平變化GPIO水龍頭輸出模式&…

Java中最常用的設計模式

Java設計模式之結構型—代理模式-CSDN博客 觀察者模式詳解-CSDN博客 單例模式詳解-CSDN博客 Java設計模式之結構型—享元模式-CSDN博客 Java設計模式之創建型—建造者模式-CSDN博客 Java設計模式之結構型—工廠模式-CSDN博客 Java設計模式之結構型—適配器模式-CSDN博客 …

使用Axure動態面板制作輪播圖案例詳解

在現代網頁設計中&#xff0c;輪播圖&#xff08;Carousel&#xff09;是一種常見且高效的展示方式&#xff0c;用于在同一空間內循環展示多張圖片或內容。Axure RP作為一款強大的原型設計工具&#xff0c;提供了動態面板和豐富的交互事件功能&#xff0c;使得制作輪播圖變得簡…