最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文詳解C#中方法重載的底層玩法

 更新時(shí)間:2022年06月15日 14:37:07   作者:一線碼農(nóng)  
最近在看C++的方法重載,就在想C#中的重載底層是怎么玩的。畢竟很多朋友應(yīng)該知道C是不支持重載的。本文將來(lái)詳細(xì)講講C#中方法重載的底層玩法,感興趣的可以了解一下<BR>

最近在看 C++ 的方法重載,我就在想 C# 中的重載底層是怎么玩的,很多朋友應(yīng)該知道 C 是不支持重載的,比如下面的代碼就會(huì)報(bào)錯(cuò)。

#include <stdio.h>

int say() {
	return 1;
}
int say(int i) {
	return i;
}

int main()
{
	say(10);
	return 0;
}

從錯(cuò)誤信息看,它說(shuō) say 方法已經(jīng)存在了,尷尬。。。

一:為什么 C 不支持

要想尋找答案,需要了解一點(diǎn)點(diǎn)底層知識(shí),那就是編譯器在編譯 C 方法時(shí)會(huì)將函數(shù)名作為符號(hào)添加到符號(hào)表中,這個(gè)符號(hào)表 就是call到say方法字節(jié)碼中間的一個(gè)載體,畫個(gè)圖大概就是這樣。

簡(jiǎn)而言之,call 先跳轉(zhuǎn)到符號(hào)表, 然后再 jmp 到 say 方法,問(wèn)題就出現(xiàn)在這里,符號(hào)表是一種類字典結(jié)構(gòu),是不可以出現(xiàn)符號(hào)相同的情況。對(duì)了,在 windbg 中我們可以用 x 命令去搜索這些符號(hào),

為了論證我的說(shuō)法,可以在匯編層面給大家驗(yàn)證下,修改代碼如下:

#include <stdio.h>

int say(int i) {
	return i;
}

int main()
{
	say(10);
	return 0;
}

接下來(lái)再看下匯編。

--------------- say(10) -----------

00C41771  push        0Ah  
00C41773  call        _say (0C412ADh)  

--------------- 符號(hào)表 -----------

00C412AD  jmp         say (0C417B0h)  

--------------- say body -----------

00C417B0  push        ebp  
00C417B1  mov         ebp,esp  
00C417B3  sub         esp,0C0h  
00C417B9  push        ebx  
00C417BA  push        esi  
00C417BB  push        edi  
00C417BC  mov         edi,ebp  
00C417BE  xor         ecx,ecx  
00C417C0  mov         eax,0CCCCCCCCh  
00C417C5  rep stos    dword ptr es:[edi]  
00C417C7  mov         ecx,offset _2440747F_ConsoleApplication6@c (0C4C008h)  
...

知道了原理后,我們?cè)倏纯?C++ 是如何在符號(hào)表上實(shí)現(xiàn)唯一性突破。

二:C++ 符號(hào)表突破

為了方便講述,我們先上一段 C++ 方法重載的代碼。

using namespace std;

class Person
{
public:
	void sayhello(int i) {
		cout << i << endl;
	}
	void sayhello(const char* c) {
		cout << c << endl;
	}
};

int main(int argc)
{
	Person person;

	person.sayhello(10);
	person.sayhello("hello world");
}

按理說(shuō) sayhello 有多個(gè),肯定是無(wú)法突破的,帶著好奇心我們看下它的反匯編代碼。

----------     person.sayhello(10);  ----------------

003B2E5F  push        0Ah  
003B2E61  lea         ecx,[person]  
003B2E64  call        Person::sayhello (03B13A2h) 

------------  person.sayhello("hello world"); ----------------

003B2E69  push        offset string "hello world" (03B9C2Ch)  
003B2E6E  lea         ecx,[person]  
003B2E71  call        Person::sayhello (03B1302h) 

從匯編代碼看, 調(diào)的都是 Person::sayhello 這個(gè)符號(hào),奇怪的是他們屬于不同的地址: 03B13A2h03B1302h,這就太奇怪了,哈哈,字典類符號(hào)表肯定是沒(méi)有問(wèn)題的,問(wèn)題是 Visual Studio 20222 的反匯編窗口在調(diào)試時(shí)做了一些內(nèi)部轉(zhuǎn)換,算是蒙蔽了我們雙眼吧,

真是可氣!??!居然運(yùn)行時(shí)匯編代碼都還不夠徹底,那現(xiàn)在我們?cè)趺蠢^續(xù)挖呢? 可以用 IDA 去看這個(gè)程序的靜態(tài)反匯編代碼,截圖如下:

從代碼上的注釋可以清楚的看到,原來(lái):

  • Person::sayhello(int) 變成了 j_?sayhello@Person@@QAEXH@Z。
  • Person::sayhello(char const *) 變成了 j_?sayhello@Person@@QAEXPBD@Z

到這里終于搞清楚了,原來(lái) C++ 為了支持方法重載,將方法名做了重新編碼,這樣確實(shí)可以突破符號(hào)表的唯一性限制。

三:C#如何實(shí)現(xiàn)突破

我們都知道 C# 的底層 CLR 是由 C++ 寫的,所以大概率玩法都是一樣,接下來(lái)上一段代碼:

    internal class Program
    {
        static void Main(string[] args)
        {
			//故意做一次重復(fù)
            Say(10);
            Say("hello world");

            Say(10);
            Say("hello world");
            Console.ReadLine();
        }

        static void Say(int i)
        {
            Console.WriteLine(i);
        }

        static void Say(string s)
        {
            Console.WriteLine(s);
        }
    }

由于 C# 的方法是由 JIT 在運(yùn)行時(shí)動(dòng)態(tài)編譯的,并且首次編譯方法會(huì)先跳轉(zhuǎn)到 JIT 的樁地址,所以斷點(diǎn)必須下在第二次調(diào)用 Say(10) 處才能看到方法的符號(hào)地址,匯編代碼如下:

 -----------	Say(10);	-----------

00007FFB82134DFC  mov         ecx,0Ah  
00007FFB82134E01  call        Method stub for: ConsoleApp1.Program.Say(Int32) (07FFB81F6F118h)  
00007FFB82134E06  nop  

-----------	Say("hello world");		-----------

00007FFB82134E07  mov         rcx,qword ptr [1A8C65E8h]  
00007FFB82134E0F  call        Method stub for: ConsoleApp1.Program.Say(System.String) (07FFB81F6F120h)  
00007FFB82134E14  nop  

從輸出信息看,同樣也是兩個(gè)符號(hào)表地址,然后由符號(hào)表地址 jmp 到最后的方法體。

-----------	Say(10);	-----------
00007FFB82134E01  call        Method stub for: ConsoleApp1.Program.Say(Int32) (07FFB81F6F118h)  

-----------	符號(hào)表	-----------
00007FFB81F6F118  jmp         ConsoleApp1.Program.Say(Int32) (07FFB82134F10h)  

-----------	Say body -----------

00007FFB82134F10  push        rbp  
00007FFB82134F11  push        rdi  
00007FFB82134F12  push        rsi  
00007FFB82134F13  sub         rsp,20h  
00007FFB82134F17  mov         rbp,rsp  
00007FFB82134F1A  mov         dword ptr [rbp+40h],ecx  
00007FFB82134F1D  cmp         dword ptr [7FFB82036B80h],0  
00007FFB82134F24  je          ConsoleApp1.Program.Say(Int32)+01Bh (07FFB82134F2Bh)  
00007FFB82134F26  call        00007FFBE1C2CC40  

暫時(shí)還不知道怎么看 JIT 改名后方法名,有知道的朋友可以留言一下哈,但總的來(lái)說(shuō)還是 C++ 這一套。

以上就是一文詳解C#中方法重載的底層玩法 的詳細(xì)內(nèi)容,更多關(guān)于C#方法重載的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#利用SharpPcap實(shí)現(xiàn)網(wǎng)絡(luò)包捕獲嗅探

    C#利用SharpPcap實(shí)現(xiàn)網(wǎng)絡(luò)包捕獲嗅探

    這篇文章主要為大家詳細(xì)介紹了C#利用SharpPcap實(shí)現(xiàn)網(wǎng)絡(luò)包捕獲嗅探,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • 使用C#實(shí)現(xiàn)生成一個(gè)綠色文件

    使用C#實(shí)現(xiàn)生成一個(gè)綠色文件

    這篇文章主要為大家詳細(xì)介紹了如何使用C#實(shí)現(xiàn)生成一個(gè)綠色文件,可以免去安裝的繁瑣過(guò)程,直接運(yùn)行,非常方便,有需要的小伙伴可以參考一下
    2024-04-04
  • C#中的隨機(jī)數(shù)函數(shù)Random()

    C#中的隨機(jī)數(shù)函數(shù)Random()

    這篇文章介紹了C#生成隨機(jī)數(shù)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • unity3D實(shí)現(xiàn)攝像機(jī)抖動(dòng)特效

    unity3D實(shí)現(xiàn)攝像機(jī)抖動(dòng)特效

    這篇文章主要為大家詳細(xì)介紹了unity3D實(shí)現(xiàn)攝像機(jī)抖動(dòng)特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-01-01
  • C#中abstract的用法詳解

    C#中abstract的用法詳解

    abstract可以用來(lái)修飾類,方法,屬性,索引器和時(shí)間,這里不包括字段. 使用abstrac修飾的類,該類只能作為其他類的基類,不能實(shí)例化,而且abstract修飾的成員在派生類中必須全部實(shí)現(xiàn),不允許部分實(shí)現(xiàn),否則編譯異常
    2016-12-12
  • C#創(chuàng)建二叉搜索樹的方法

    C#創(chuàng)建二叉搜索樹的方法

    這篇文章主要介紹了C#創(chuàng)建二叉搜索樹的方法,涉及C#二叉搜索樹的實(shí)現(xiàn)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2015-04-04
  • Unity實(shí)現(xiàn)菜品識(shí)別的示例代碼

    Unity實(shí)現(xiàn)菜品識(shí)別的示例代碼

    這篇文章主要介紹了如何通過(guò)Unity實(shí)現(xiàn)菜品識(shí)別,可以準(zhǔn)確識(shí)別圖片中的菜品名稱、位置、卡路里信息,并獲取百科信息。感興趣的小伙伴可以了解一下
    2022-02-02
  • ListView Adapter優(yōu)化 實(shí)例

    ListView Adapter優(yōu)化 實(shí)例

    ListView Adapter優(yōu)化 實(shí)例,需要的朋友可以參考一下
    2013-04-04
  • C# 參數(shù)按照ASCII碼從小到大排序(字典序)

    C# 參數(shù)按照ASCII碼從小到大排序(字典序)

    這篇文章主要介紹了C# 參數(shù)按照ASCII碼從小到大排序(字典序)的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-04-04
  • unity 鼠標(biāo)懸停事件操作

    unity 鼠標(biāo)懸停事件操作

    這篇文章主要介紹了unity 鼠標(biāo)懸停事件操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04

最新評(píng)論

乐昌市| 台山市| 永靖县| 夏河县| 吕梁市| 滨海县| 曲松县| 开远市| 浦县| 正镶白旗| 德庆县| 始兴县| 泰兴市| 涞源县| 库尔勒市| 六盘水市| 大荔县| 阳朔县| 黑河市| 秦安县| 湟源县| 郑州市| 宿松县| 莎车县| 宁津县| 密山市| 瓮安县| 灵寿县| 上杭县| 清水河县| 当雄县| 南丹县| 郓城县| 石狮市| 灵台县| 保德县| 博爱县| 喜德县| 沙雅县| 太仆寺旗| 竹山县|