1. 程式人生 > >gcc之inline函式探究

gcc之inline函式探究

1、引子:行內函數(以下稱為inline函式)的行為類似於巨集,但是會像函式一樣進行引數的靜態型別檢查。因此gcc中很多地方傾向於使用inline函式來替代巨集。但是inline函式在gcc中應該如何使用呢?函式被內聯之後究竟有哪些改變呢?

#include "stdio.h"

//inline int func(int a) __attribute__((always_inline));  // func有,內聯成功puts
//inline int func(int a);          // func有,未內聯
//int func(int a) __attribute__((noinline));     // func有,未內聯


//static inline int func(int a) __attribute__((always_inline)); // func無,內聯成功puts
//static inline int func(int a);        // func有,未內聯
//static int func(int a) __attribute__((noinline));    // func有,未內聯

//extern inline int func(int a) __attribute__((always_inline)); // func有,未內聯
//extern inline int func(int a);        // func有,未內聯
//extern int func(int a) __attribute__((noinline));    // func有,未內聯


int func(int a)
{
 a += 5; 
 printf("inline test, a = %d\n", a);
}

int main(void)
{
 func(5);
 func(6);
 func(7);
  
 return 0;
}
2、測試方法:
測試程式碼如上,非常簡單的一個函式func,func在主程式中被呼叫3次。我們分別使用上面三組、每組三個的宣告方式來對func函式進行宣告。然後使用gcc inline.c -o xx 來進行編譯連結,生成可執行檔案xx,然後用objdump xx -d > xx.txt來對剛才生成的可執行程式進行反彙編,得到對應的彙編程式碼。這裡的xx在每種宣告方式下不同,我採用組號+組內編號的形式來命名,如第一種宣告方式xx為11,而最後一種宣告方式中xx為33。
測試後檢視反彙編程式碼xx.txt,重點關注兩個問題:
2.1、func有無被內聯處理?
2.2、func函式在最終的可執行程式中有沒有生成獨立程式碼段
3、結果分析:
3.1、實際的測試結果如9種宣告之後標註的,即只有11和21這兩種下func被內聯處理,其他情況下都未內聯。這是__attribute__((always_inline))產生的影響。比較有趣的是31也未被內聯,儘管使用了強制內聯,但是在extern inline下還是不進行內聯處理,這也是跟網上查到的一些資料不符的地方。
3.2、21中func未生成獨立程式碼段,而其他均有生成。這個很好理解,因為static宣告的函式只會被該文字內引用而不會被外部引用,而inline之後該文字內所有對func的引用都被內聯了,因此func沒有必要再生成獨立的程式碼段了。(程式中func本身不是遞迴函式,而且func未被賦值給某一函式指標)
4、反彙編程式碼很長很多,這裡只貼出兩組來。一是11,二是12。因為這兩組可以代表其他的情況了。而且只貼出func和main兩個函式相關的程式碼段:
-----------11.txt片段--------------------

080483e4 <func>:
 80483e4: 55                    push   %ebp
 80483e5: 89 e5                 mov    %esp,%ebp
 80483e7: 83 ec 18              sub    $0x18,%esp
 80483ea: 83 45 08 05           addl   $0x5,0x8(%ebp)
 80483ee: b8 40 85 04 08        mov    $0x8048540,%eax
 80483f3: 8b 55 08              mov    0x8(%ebp),%edx
 80483f6: 89 54 24 04           mov    %edx,0x4(%esp)
 80483fa: 89 04 24              mov    %eax,(%esp)
 80483fd: e8 1a ff ff ff        call   804831c <[email protected]>
 8048402: c9                    leave 
 8048403: c3                    ret   

08048404 <main>:
 8048404: 55                    push   %ebp
 8048405: 89 e5                 mov    %esp,%ebp
 8048407: 83 e4 f0              and    $0xfffffff0,%esp
 804840a: 83 ec 20              sub    $0x20,%esp
 804840d: c7 44 24 1c 05 00 00  movl   $0x5,0x1c(%esp)
 8048414: 00
 8048415: 83 44 24 1c 05        addl   $0x5,0x1c(%esp)
 804841a: b8 40 85 04 08        mov    $0x8048540,%eax
 804841f: 8b 54 24 1c           mov    0x1c(%esp),%edx
 8048423: 89 54 24 04           mov    %edx,0x4(%esp)
 8048427: 89 04 24              mov    %eax,(%esp)
 804842a: e8 ed fe ff ff        call   804831c <[email protected]>
 804842f: c7 44 24 18 06 00 00  movl   $0x6,0x18(%esp)
 8048436: 00
 8048437: 83 44 24 18 05        addl   $0x5,0x18(%esp)
 804843c: b8 40 85 04 08        mov    $0x8048540,%eax
 8048441: 8b 54 24 18           mov    0x18(%esp),%edx
 8048445: 89 54 24 04           mov    %edx,0x4(%esp)
 8048449: 89 04 24              mov    %eax,(%esp)
 804844c: e8 cb fe ff ff        call   804831c <[email protected]>
 8048451: c7 44 24 14 07 00 00  movl   $0x7,0x14(%esp)
 8048458: 00
 8048459: 83 44 24 14 05        addl   $0x5,0x14(%esp)
 804845e: b8 40 85 04 08        mov    $0x8048540,%eax
 8048463: 8b 54 24 14           mov    0x14(%esp),%edx
 8048467: 89 54 24 04           mov    %edx,0x4(%esp)
 804846b: 89 04 24              mov    %eax,(%esp)
 804846e: e8 a9 fe ff ff        call   804831c <[email protected]>
 8048473: b8 00 00 00 00        mov    $0x0,%eax
 8048478: c9                    leave 
 8048479: c3                    ret   
 804847a: 90                    nop
 804847b: 90                    nop
 804847c: 90                    nop
 804847d: 90                    nop
 804847e: 90                    nop
 804847f: 90                    nop


----------12.txt片段----------------------

080483e4 <func>:
 80483e4: 55                    push   %ebp
 80483e5: 89 e5                 mov    %esp,%ebp
 80483e7: 83 ec 18              sub    $0x18,%esp
 80483ea: 83 45 08 05           addl   $0x5,0x8(%ebp)
 80483ee: b8 00 85 04 08        mov    $0x8048500,%eax
 80483f3: 8b 55 08              mov    0x8(%ebp),%edx
 80483f6: 89 54 24 04           mov    %edx,0x4(%esp)
 80483fa: 89 04 24              mov    %eax,(%esp)
 80483fd: e8 1a ff ff ff        call   804831c <[email protected]>
 8048402: c9                    leave 
 8048403: c3                    ret   

08048404 <main>:
 8048404: 55                    push   %ebp
 8048405: 89 e5                 mov    %esp,%ebp
 8048407: 83 e4 f0              and    $0xfffffff0,%esp
 804840a: 83 ec 10              sub    $0x10,%esp
 804840d: c7 04 24 05 00 00 00  movl   $0x5,(%esp)
 8048414: e8 cb ff ff ff        call   80483e4 <func>
 8048419: c7 04 24 06 00 00 00  movl   $0x6,(%esp)
 8048420: e8 bf ff ff ff        call   80483e4 <func>
 8048425: c7 04 24 07 00 00 00  movl   $0x7,(%esp)
 804842c: e8 b3 ff ff ff        call   80483e4 <func>
 8048431: b8 00 00 00 00        mov    $0x0,%eax
 8048436: c9                    leave 
 8048437: c3                    ret   
 8048438: 90                    nop
 8048439: 90                    nop
 804843a: 90                    nop
 804843b: 90                    nop
 804843c: 90                    nop
 804843d: 90                    nop
 804843e: 90                    nop
 804843f: 90                    nop

相關推薦

gccinline函式探究

1、引子:行內函數(以下稱為inline函式)的行為類似於巨集,但是會像函式一樣進行引數的靜態型別檢查。因此gcc中很多地方傾向於使用inline函式來替代巨集。但是inline函式在gcc中應該如何使用呢?函式被內聯之後究竟有哪些改變呢? #include "stdio.

C++inline函式使用總結

一、C++為什麼引入inline函式? 主要目的:用它代替C語言中表達式形式的巨集定義來解決程式中函式呼叫的效率問題。C語言中的巨集定義,它使用前處理器實現,沒有了引數壓棧、程式碼生成等一系列得到操作,因此效率很高。 但缺點如下: 前處理器符號表中的簡單替換,不能進行引數有

Effective C++筆記十五:inline函式的裡裡外外

1.inline函式簡介 inline函式是由inline關鍵字來定義,引入inline函式的主要原因是用它替代C中複雜易錯不易維護的巨集函式。 2.編譯器對inline函式的處理辦法 inline對於編譯器而言,在編譯階段完成對inline函式的處理。將呼叫動作替換為函式的本體。但是它只是一種

小問題大思考C++裡的inline函式

inline,一個神奇的關鍵字。有了它,你同時就可以獲取函式和巨集的優點。inline定義的函式,比起沒有inline的函式來說,沒有執行函式呼叫所帶來的負擔(對此可參見《C++程式的記憶體佈局》),因此它是高效率的;比起巨集來,它具有函式的可預期行為和引數型別檢驗。巨集的

c++筆記CArray函式

謹以此文獻給因為我菜雞同時裝了VS2013和2017導致vs各種衝突,以至於只能重灌系統的新電腦!哭泣.... CArray屬於MFC,是一個數組模板類。MFC的陣列類支援的陣列類似於常規陣列,可以存放任何資料型別。常規陣列在使用前必須將其定義成能夠容納所有可能需要的元素,即先確定大小,而M

gcc與g++的探究

Windows中我們常用vs來編譯編寫好的C和C++程式碼;vs把編輯器,編譯器和偵錯程式等工具都整合在這一款工具中,在Linux下我們能用什麼工具來編譯所編寫好的程式碼呢,其實Linux下這樣的工具有很多,但我們只介紹兩款常用的工具,它們分別是gcc和g++. 工具用法介紹 gcc和g++的用

Shellfunction函式的定義及呼叫

文章目錄 `function`函式的定義及呼叫 `function`函式的定義 `function`函式的呼叫【位置傳參】 函式使用return返回值【位置傳參】 函式的呼叫【陣列傳參】

Excel操作VLOOKUP函式

1、作用   VLOOKUP函式是Excel中的一個縱向查詢函式,它與LOOKUP函式和HLOOKUP函式屬於一類函式,在工作中都有廣泛應用,例如可以用來核對資料,多個表格之間快速匯入資料等函式功能。功能是按列查詢,最終返回該列所需查詢列序所對應的值;與之對應的HLOOKUP是按行查詢的。 2、語法規則

golang教程一類函式

文章目錄 一類函式 什麼是一類函式? 匿名函式 使用者定義的函式型別 高階函式 從其他函式返回函式 閉包 一類函式的使用 一類函式 原文:https://golan

Function Read_Text 函式的使用方法

在SAP系統中,有時候會有大段文字內容需要儲存.例如:銷售發貨(VL03N),在單據的概覽中 ,有一個[文字]項,在此處可以填寫單據的大段文字描述,那麼該內容儲存在哪裡呢?第一反應是找對應表的欄位,那麼你可能要失望了。在SAP系統中,可以供我們使用的資料庫欄位最大長度是255個文字字元(注:此處可能

地理位置geo處理mysql函式

目前越來越多的業務都會基於LBS,附近的人,外賣位置,附近商家等等,現就討論離我最近這一業務場景的解決方案。 原文:https://www.jianshu.com/p/455d0468f6d4 目前已知解決方案有: mysql 自定義函式計算

Python函式系統函式的呼叫

全部測試程式碼 #!/usr/bin/evn python3 #_*_conding:utf-8 _*_ #系統內建函式 #1.abs():檢視絕對值,如果傳入的引數不對,會報TypeError print('-100的絕對值--',abs(-100)) #2.max():檢

學渣學pythonmap函式

map()函式是Python內建的高階函式,它接收一個函式f和一個list,並把函式f作用在list的每個元素上。從而得到一個f處理過的新的list返回。下面舉個栗子: 1. 例1 list [1, 2, 3, 4, 5, 6, 7] 我們要得到list的每個元素都平方後的,新的li

pytho系統學習:第二週字串函式練習

# Author : Sunny# 雙下劃線的函式基本沒用# 定義字串name = 'i am sunny!'# 首字母大寫函式:capitalizeprint('-->capitalize:', name.capitalize())# 判斷結尾函式:endswithprint('-->endsw

matlabsortrows()函式

sortrows()函式的格式: sortrows(A,column) A是一個矩陣,如果沒有第二個引數column,則預設按照第一列升序排列,如果遇到重複數字,則按照第二列升序排列,依次類推。。。 如果存在第二個引數column,則按照指定的列排序,當指定的列有重複元素的時候,則重複元素所在的行保持原

Promise原始碼閱讀建構函式+then過程

前言 Promise是非同步程式設計的一種方案,ES6規範中將其寫入規範標準中,統一了用法。 考慮到瀏覽器的相容性,Vue專案中使用promise,就具體閱讀promise原始碼,看看內部的具體實現。 具體分析 通過具體例項來閱讀promise原始碼的實現,例項如下: new

C# socket 程式設計 accept() 函式返回值解析

accept() 函式會返回一個新的套接字,這個新的套接字在伺服器端與客戶端進行通訊。 伺服器端的繫結監聽是一個套接字,與客戶端通訊的是另一個套接字(accept函式返回的套接字,注意這裡不是返回客戶端的套接字,返回的套接字是新建立在伺服器上的,與客戶端收發訊息用的) 下面這段程式碼,是

KMP演算法next函式解釋(大量的反證法 和數學歸納法來襲)

先放get_nextval()函式的程式碼 void get_nextval(const char str[],int *net) { net[0]=-1; int j=0,k=-1,len; len=strlen(str); while(j<len)

STL查詢函式

STL之二分查詢 (Binary search in STL) Section I 正確區分不同的查詢演算法count,find,binary_search,lower_bound,upper_bound,equal_range 本文是對Effective STL第45條的一個總結,闡述了各種

HashMap原始碼建構函式--JDK1.8

建構函式 變數解釋 capacity,表示的是hashmap中桶的數量,初始化容量initCapacity為16,第一次擴容會擴到64,之後每次擴容都是之前容量的2倍,所以容量每次都是2的次冪 loadFactor,負載因子,衡量hashmap一個滿的程度,初始預設為0.75 thresho