欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言匯編分析傳遞結(jié)構(gòu)體指針比傳遞結(jié)構(gòu)體變量高效的深層原因

 更新時間:2022年10月19日 14:24:53   作者:是星星鴨  
本文章使用的工具是vs2010,本篇文章主要講解結(jié)構(gòu)體指針作為參數(shù)傳遞與結(jié)構(gòu)體變量作為參數(shù)傳遞的對比,不談值傳遞與址傳遞的概念

前言

先聲明下觀點:當有少量結(jié)構(gòu)體成員時,傳遞結(jié)構(gòu)體指針和結(jié)構(gòu)體變量的差距不大;當有大量結(jié)構(gòu)體成員時,隨著成員越來越多,傳遞指針的效率也越來越高,與傳遞變量的差距也越來越大。

傳遞結(jié)構(gòu)體變量

直接看代碼:

測試程序demo01.cpp,如下:

#include <stdio.h>
#include <Windows.h>
struct st_info                    // 定義結(jié)構(gòu)體
{
    int x;
    int y;
    int m;
    int n;
};
int retAddst(st_info stinfo)      // 函數(shù)返回結(jié)構(gòu)體變量成員相加的值
{
    return stinfo.x+stinfo.y+stinfo.m+stinfo.n;
}
int main()
{
    st_info stinfo = {1,2,3,4};   // 定義變量準備傳參。
    int r = retAddst(stinfo);     // 接收返回值,此處設(shè)置斷點查看反匯編
    return 0;
}

vs2010:斷點、F7編譯、F5調(diào)試、ALT+8轉(zhuǎn)到反匯編

如下:

當看到這段匯編代碼的實現(xiàn)的時候,可能對于新手都不太友好,因為之前對于函數(shù)的調(diào)用時,匯編代碼大多都是使用push進行傳參,但是這里調(diào)用函數(shù)卻沒有用到push,那他是怎么實現(xiàn)的呢?

我們畫堆棧圖逐步分析:

堆棧:

匯編:

堆棧:

匯編:

堆棧:

匯編:

堆棧:

匯編:

堆棧:

匯編:

堆棧:

然后下面就是調(diào)用函數(shù),讓我們看看函數(shù)中是怎么使用的

單步F11進入函數(shù)內(nèi)部:

匯編:

這里我直接給出堆棧結(jié)果,不懂得可以看我之前的文章《堆棧圖》

匯編:

對應(yīng)堆棧:

可以看出,雖然沒有使用push進行參數(shù)的傳遞,但是他還是使用堆棧,使用ebp尋址來實現(xiàn)的函數(shù)參數(shù)的查找。

為什么說傳遞結(jié)構(gòu)體變量性能不高?

我們來分析匯編:

為什么這叫拷貝?

拷貝的概念就是,在不影響原值的情況下,在另外一個地址中也存放一個同樣的值

我們可以發(fā)現(xiàn),我們mov指令并不會刪除我們之前定義在main函數(shù)局部變量區(qū)域中的1,2,3,4,并且還復(fù)制了一份到esp、esp+4...這些地址中,所以這就是拷貝。

一次拷貝需要從原地址中取一次值、然后放到寄存器、最終放到目標地址,是不是很麻煩?但是如果結(jié)構(gòu)體變量中需要用到四個成員,那么就需要進行四次拷貝,如果成員越來越多,拷貝的次數(shù)也就越來越多......

結(jié)構(gòu)體成員拷貝的壞處

隨著拷貝次數(shù)越來越多,不但會影響性能,也會使匯編代碼顯得非常臃腫。

解決方法就是傳指針。

傳遞結(jié)構(gòu)體指針

按照我們對傳遞指針的理解,我們認為傳遞變量的指針就是傳遞他的地址,那么既然有了這個變量的地址了,是不是就不需要拷貝了?

測試程序demo01,代碼如下:

#include <stdio.h>
#include <Windows.h>
struct st_info                    // 定義結(jié)構(gòu)體
{
    int x;
    int y;
    int m;
    int n;
};
int retAddst(st_info* stinfo)      // 函數(shù)返回結(jié)構(gòu)體變量成員相加的值
{
    return stinfo->x+stinfo->y+stinfo->m+stinfo->n;
}
int main()
{
    st_info stinfo = {1,2,3,4};   // 定義變量準備傳參。
    int r = retAddst(&stinfo);     // 接收返回值,此處設(shè)置斷點查看反匯編
    return 0;
}

重新生成、調(diào)試、反匯編:

lea eax,[ebp-18h]

通過上面將1存入[ebp-18h]我們知道ebp-18h就是結(jié)構(gòu)體第一個成員的地址,也就是結(jié)構(gòu)體的首地址,所以這里我們僅僅是傳遞了結(jié)構(gòu)體的首地址

(注意:lea指令是將ebp-18h這個地址賦值給eax,而不是將地址中的1賦值給eax)

與傳遞結(jié)構(gòu)體變量的匯編對比:

1、首先我們一眼就能看出,匯編代碼變得整潔了。

2、傳遞結(jié)構(gòu)體變量的匯編中,雖然找不到push,但是我們進入函數(shù)中分析,發(fā)現(xiàn)它使用的依舊是堆棧、并且最后平衡堆棧的時候是add esp+10h,不算函數(shù)提升堆棧的使用,總共使用了16字節(jié)的堆棧;

然而對于傳遞指針,最終只是add esp,4;只使用了4個自己的堆棧。并且隨著結(jié)構(gòu)體的成員越來越多、差距會越來越大。

對于傳遞指針,函數(shù)內(nèi)部是如何使用的呢?

如下:

可能看到這里,會有人問:這不是和傳遞結(jié)構(gòu)體變量傳參的代碼差不多嗎?因為單從匯編代碼上來觀察,貌似都長得很像,但是還是有區(qū)別的。

傳遞變量時,我們是將原堆棧中的值取出放到寄存器、然后寄存器放到新的堆棧中

傳遞地址時,我們是將首地址放到寄存器中,然后取出該地址中的值又放到寄存器中

區(qū)別呢?

三種方法看出傳遞變量與傳遞指針的差距

<1>

傳遞變量:堆棧->寄存器->新堆棧

傳遞指針:堆棧->寄存器->寄存器

我們之前說過,使用內(nèi)存(堆棧)是絕對沒有使用cpu(寄存器)的效率高的,所以這也能看出傳遞地址是比傳遞變量效率高的。

<2>

傳遞變量:add esp,10h

傳遞指針:add esp,04h

當我們傳遞變量時,我們可以發(fā)現(xiàn),底層匯編是不斷的將源地址中的值取出放到堆棧中的,一個使用了16個字節(jié);但是傳遞地址只用到了四個字節(jié)的堆棧,就是用來存放結(jié)構(gòu)體的首地址。這樣一來,傳遞變量內(nèi)存使用比傳遞指針要多。當然,我們結(jié)構(gòu)體成員越多,傳遞變量使用到的堆棧就越多,而傳遞指針還是只是用4個字節(jié)堆棧存放結(jié)構(gòu)體首地址,二者的差距會越來越大。

<3>

傳遞變量與傳遞地址的時候,我們都是先將結(jié)構(gòu)體成員存放到main函數(shù)的局部變量區(qū)域中,也就是下面這一塊:

但是傳遞變量的時候,它是將這四個值1,2,3,4拿出來又放進去的,操作是很頻繁的。相反傳遞地址的時候只是把【ebp-18h】這個地址放進去。一個操作四次、一個操作一次,差距一眼就能看出來。

總結(jié)

通過上面的對比,我們可以看出傳遞指針的效率是比傳遞變量效率高的。這個差距會隨著結(jié)構(gòu)體成員個數(shù)的提升而提升。所以,建議傳遞結(jié)構(gòu)體指針。

到此這篇關(guān)于C語言匯編分析傳遞結(jié)構(gòu)體指針比傳遞結(jié)構(gòu)體變量高效的深層原因的文章就介紹到這了,更多相關(guān)C語言匯編分析內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++ Boost log日志庫超詳細講解

    C++ Boost log日志庫超詳細講解

    Boost是為C++語言標準庫提供擴展的一些C++程序庫的總稱。Boost庫是一個可移植、提供源代碼的C++庫,作為標準庫的后備,是C++標準化進程的開發(fā)引擎之一,是為C++語言標準庫提供擴展的一些C++程序庫的總稱
    2022-11-11
  • 用C語言遞歸實現(xiàn)火車調(diào)度算法詳解

    用C語言遞歸實現(xiàn)火車調(diào)度算法詳解

    本文主要介紹了用C語言遞歸實現(xiàn)火車調(diào)度算法詳解,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • C語言實現(xiàn)選擇題標準化考試系統(tǒng)

    C語言實現(xiàn)選擇題標準化考試系統(tǒng)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)選擇題標準化考試系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • C語言實現(xiàn)小小圣誕樹源代碼

    C語言實現(xiàn)小小圣誕樹源代碼

    圣誕節(jié)當然要有個圣誕樹了,今天給你們用C語言編寫一個雪夜圣誕樹,這篇文章主要給大家介紹了關(guān)于C語言實現(xiàn)小小圣誕樹的相關(guān)資料,需要的朋友可以參考下
    2023-12-12
  • C++實現(xiàn)簡易的五子棋小游戲

    C++實現(xiàn)簡易的五子棋小游戲

    這篇文章主要為大家詳細介紹了C++實現(xiàn)簡易的五子棋小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • C語言實現(xiàn)三子棋游戲(棋盤可變)

    C語言實現(xiàn)三子棋游戲(棋盤可變)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)三子棋游戲,棋盤可變,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • wince禁止程序標題欄上的退出按鈕示例

    wince禁止程序標題欄上的退出按鈕示例

    這篇文章主要介紹了wince禁止程序標題欄上的退出按鈕示例,需要的朋友可以參考下
    2014-02-02
  • C語言如何實現(xiàn)頭插法建立單鏈表

    C語言如何實現(xiàn)頭插法建立單鏈表

    這篇文章主要介紹了C語言實現(xiàn)頭插法建立單鏈表的方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • C語言中#define定義的標識符和宏實例代碼

    C語言中#define定義的標識符和宏實例代碼

    C語言中,可以用#define定義一個標識符來表示一個常量,下面這篇文章主要給大家介紹了關(guān)于C語言中#define定義的標識符和宏的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-03-03
  • C語言數(shù)據(jù)結(jié)構(gòu)之二叉鏈表創(chuàng)建二叉樹

    C語言數(shù)據(jù)結(jié)構(gòu)之二叉鏈表創(chuàng)建二叉樹

    這篇文章主要介紹了C語言數(shù)據(jù)結(jié)構(gòu)之?二叉鏈表創(chuàng)建二叉樹,下文我們?yōu)榱烁奖愕氖褂枚鏄浣Y(jié)構(gòu)體,可以使用?typedef?對結(jié)構(gòu)體進行命名,具體內(nèi)容需要的小伙伴可以參考一下
    2022-02-02

最新評論