最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

第 27 講:指針(四):和底層的互操作

2021-04-11 09:32 作者:SunnieShine  | 我要投稿

本文難度較大,是因?yàn)檫@個(gè)概念是 C 語言沒有的,因此理解起來比較困難;相反,這個(gè)編程語言允許和 C 語言的代碼進(jìn)行交互使用。

另外,這篇文章可以考慮在以后學(xué)習(xí)了其它的知識(shí)點(diǎn)后,再來回頭看。反正也不是很重要。

Part 1 互操作性

互操作性(也叫交互性,Interoperability),指的是 C# 的代碼上可以跑 C 和 C++ 的程序的代碼。從另外一個(gè)角度來說,由于我們?cè)试S使用這樣的機(jī)制來執(zhí)行程序,因此我們可以允許 C# 跑 Linux 上的 C 語言程序,因此平臺(tái)不相同了。所以,這個(gè)情況一般也可以記作 P/Invoke。

其中 P/Invoke 的 P 是 Platform(平臺(tái))的縮寫。所以 P/Invoke 也就叫做平臺(tái)調(diào)用。

我們來舉個(gè)例子。由于我們是黑框程序(控制臺(tái)),因此我們想要用彈窗告知用戶一些信息。但是,C# 的控制臺(tái)又不是平時(shí)肉眼所見的彈框,因此我們需要借助別的方法來產(chǎn)生這個(gè)彈框。

我們這里要用到 C 語言和 C++ 里用的函數(shù):MessageBox。這個(gè)函數(shù)被存放在 user32.dll 這個(gè)文件里。

我們?nèi)绻褂眠@個(gè)函數(shù),如果我們要用這個(gè)函數(shù),就需要使用一個(gè)語法:[DllImport("user32")]。以方括號(hào)記號(hào)標(biāo)記在方法上方的模式叫做特性(Attribute)。

接著,因?yàn)閷戇M(jìn) C# 代碼的方法是外來導(dǎo)入的,因此這樣的方法稱為外部方法(External Method)。這樣的方法需要在簽名上添加 extern 關(guān)鍵字以表示方法是外來的。這個(gè)方法帶有四個(gè)參數(shù)分別是 void*string、stringuint,并返回一個(gè) int 類型結(jié)果。

什么?你不知道這個(gè)參數(shù)為啥是這樣?互操作性是從 C/C++ 引入的函數(shù),所以這個(gè)得網(wǎng)上搜資料才知道。這個(gè)函數(shù)的聲明并不是拿給你背的。

另外,但凡有一個(gè)參數(shù)的類型,還有返回值類型寫錯(cuò),整個(gè)程序都會(huì)崩潰,因?yàn)檫@樣的函數(shù)在文件里因?yàn)閰?shù)和返回值無法對(duì)應(yīng)起來,就會(huì)導(dǎo)致傳參失敗。

然后我們?cè)囍\(yùn)行下這個(gè)程序。你在看到控制臺(tái)打開的時(shí)候,立刻彈出一個(gè)新的白色框,提示一段文字;這些文字都是在剛才 C# 代碼里寫的這些字符串。

這就是運(yùn)行結(jié)果了。

然后提一句,這里引用 C/C++ 的函數(shù)的過程叫做調(diào)用(Invoke)。這里的調(diào)用(invoke)和之前介紹方法的調(diào)用(call)是不一樣的英語單詞,只是中文里用的是同一個(gè)詞語,在英文環(huán)境下,它們并不是一個(gè)意思。這里的調(diào)用(invoke)指的是一種“回調(diào)”過程:方法本身并不是我們控制的調(diào)用,因?yàn)榈讓拥拇a并非由我們自己實(shí)現(xiàn),而過程是自動(dòng)調(diào)用的;而相反地,方法里的調(diào)用(call)過程,是我們自己控制的,我想這么調(diào)用就這么調(diào)用。

Part 2 MarshalAs 標(biāo)記

這樣的代碼是不嚴(yán)謹(jǐn)?shù)摹R驗(yàn)榈讓訉?shí)現(xiàn)的關(guān)系,C 語言里的 int 類型大小并不是完全和 C# 語言的 int 類型正確對(duì)應(yīng)起來的,因此,我們需要指定參數(shù)在交互的時(shí)候,和 C 語言里真正對(duì)應(yīng)起來的轉(zhuǎn)換類型。

看一下這個(gè)例子。我們除了用上方的 [DllImport] 以外,還需要為參數(shù)添加 [MarshalAs] 修飾。

C 語言和 C++ 里,字符串是以 '\0' 作為終止字符的。因此,我們?cè)谥付ǖ臅r(shí)候,為了嚴(yán)謹(jǐn)需要添加 [MarshalAs(UnmanagedType.LPStr)]。這個(gè)寫法專門表示和指明這個(gè)參數(shù)在調(diào)用的時(shí)候會(huì)自動(dòng)轉(zhuǎn)換成 C 語言和 C++ 的這種字符串形式。另外,最后一個(gè)參數(shù)我們固定指定 [MarshalAs(UnmanagedType.U4)] 表示傳入的是 unsigned int 類型,大小是 4 個(gè)字節(jié)。

然后,第 4 行的 [return: MarshalAs(UnmanagedType.I4)] 實(shí)際上指的是,這個(gè)函數(shù)的返回值在底層是什么類型的。這里寫成這樣表示,底層是 C/C++ 里的 int 類型。

Part 3 調(diào)用變長(zhǎng)參數(shù)函數(shù)

在 C 語言和 C++ 里,擁有一個(gè)特殊的函數(shù)類型,叫做變長(zhǎng)參數(shù)函數(shù)。變長(zhǎng)參數(shù)使用三個(gè)小數(shù)點(diǎn)來表達(dá)。這種函數(shù)我們?cè)趺磳?C# 代碼呢?難道是 params 參數(shù)修飾嗎?

實(shí)際上不是。因?yàn)?C 語言和 C++ 里的變長(zhǎng)參數(shù)實(shí)現(xiàn)模型和 C# 的是不一樣的,因此我們需要借助一個(gè)特殊的關(guān)鍵字來完成:__arglist。這個(gè)關(guān)鍵字比較特殊的地方在于,它是以雙下劃線開頭的關(guān)鍵字。

稍微注意一下的是,我們這里要用到一個(gè)地方的修改:[DllImport] 里要在后面追加一個(gè)叫 EntryPoint = "printf" 的寫法。

這個(gè)修改是為了指定執(zhí)行的方法在 DLL 文件里名字是什么。因?yàn)?C# 的方法約定是使用大寫字母開頭的單詞,因此我們寫大寫的話,可能會(huì)導(dǎo)致這個(gè)叫 Printf 的函數(shù)在文件里找不到。因此我們追加這個(gè)東西來告知程序在處理的時(shí)候自動(dòng)去找 printf。

運(yùn)行程序。我們可以看到結(jié)果:

這就是 C# 里使用 C/C++ 里的變長(zhǎng)參數(shù)的辦法。

Part 4 總結(jié)

至此,我們就把 C# 的指針大致給大家說了一下。指針的內(nèi)容比較復(fù)雜,特別是本節(jié)的內(nèi)容可能讓你看得是一頭霧水。沒有關(guān)系。以后還有更難的東西(不是

好好學(xué)。這點(diǎn)內(nèi)容可以以后來看,至于重要不重要,我相信你自己應(yīng)該是知道的。


第 27 講:指針(四):和底層的互操作的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
墨竹工卡县| 凌源市| 六枝特区| 安新县| 武邑县| 荥阳市| 长丰县| 旅游| 鲁甸县| 永泰县| 峨眉山市| 鄂伦春自治旗| 分宜县| 瑞丽市| 普兰县| 东丰县| 万州区| 察雅县| 麟游县| 天全县| 鲁山县| 北京市| 宁德市| 安丘市| 金门县| 余姚市| 合肥市| 陆良县| 应用必备| 东宁县| 九台市| 海南省| 济南市| 泰州市| 牙克石市| 祁东县| 厦门市| 阜新市| 宣恩县| 鄂托克旗| 封开县|