2017-02-26 53 views
4

我很難理解託管C++如何工作和編譯。瞭解託管C++

在.NET Framework中,您可以使用C#/ VB/F#/ ..等開發代碼。並且所有這些語言都將被編譯爲與Java字節碼相似的通用中間語言(CIL)。從理論上講,CIL可以安裝在任何平臺上(Mono使其具有實用性)。在Windows上,CLR將CIL編譯爲本地代碼Just-In-Time(JIT),並且一切運行順利並且順利。

現在,Managed C++如何編譯?它是否編譯爲CIL代碼並等待CLR使用JIT運行它?我認爲不是,因爲Managed C++可以使用標準C++代碼(不會編譯爲CIL)。此外,它如何能夠使用.NET程序集(即CIL)?

我將不勝感激任何幫助。 感謝

編輯:

我已經看到了這answer。它指出,在C++/CLI中,託管代碼被編譯爲MSIL,並且您可以選擇將非託管代碼編譯爲本機代碼或MSIL。因此,我現在明白如何調用.NET程序集。

無論如何,如果非託管代碼被編譯爲本機代碼,我仍然不明白C++非託管代碼如何在同一程序集中的託管代碼上運行。有任何想法嗎?

回答

6

這是一個很大的話題具有非常堅韌的實施細節。很難解決所有問題,但這個問題存在一些誤解。讓我們來解決這些問題,可能有助於進入下一個階段。

此外,它如何能夠使用.NET程序集(它是CIL)?

不只是CIL,鏈接器產生了一個混合模式程序集。包含.NET元數據+ msil 本機代碼。實際上,就OS加載器而言,它是可執行文件中的正常代碼。與本機C++編譯器生成的類型沒有什麼不同。它被加載並重新定位,就像純原生可執行映像一樣。這是.NET元數據+ MSIL是古怪的。對於加載器來說,它看起來像是一大塊數據,根本不會觸及它。只有CLR可以。

...利用標準C++代碼(未編譯CIL)

不太準確,本地C++代碼可以被編譯爲MSIL 機器代碼。你得到的東西取決於/ clr編譯選項是否被使用,或者在功能級別管理的#pragma是否有效。 CIL並沒有比較好,比如在Java JVM中使用的字節碼。它功能更強大,可以支持任何C++ 03兼容的本地C++代碼。有時候你會這樣做,以便利用反向拼寫(本地代碼調用託管代碼)。有時它是偶然完成的,並且完全太多本機C++代碼被編譯爲msil。由抖動產生的機器碼不是最優的(它在時間限制下優化)並且不以任何方式進行管理。這是無法驗證的,並沒有得到垃圾收集者的喜愛。

最佳CIL心理圖像是作爲在前端(解析器)和後端(代碼發生器和優化器)之間的任何本地C++編譯器使用的中間表示。通常是一個不可見的實現細節,但在使用使用LLVM的C++編譯器時(如Clang所做的那樣)會更明顯。 .NET即時編譯器在運行時會在編譯時執行LLVM的工作。


當託管代碼調用本機代碼(或其他方式)時,大多數程序員都會產生巨型模式開關的心理圖像。這根本不準確。您可能想看看this post,它顯示了C++編譯器後端生成的機器碼和抖動之間的差異。關鍵是它幾乎完全相同,這是確保託管代碼與本機代碼競爭的基本特徵。有助於闡明調用本地代碼的託管代碼或其他方式如何不那麼特別。

另一個誤解是託管代碼自動安全。並非如此,像C#這樣的語言可以讓你用指針進行派對,並像在C++中一樣在堆棧中亂寫,並且可以像這樣輕鬆地破壞內存。它只是更好地分區,它迫使你用關鍵字unsafe來明確它。對C++/CLI沒有這樣的限制,什麼都行。

管理和本地代碼之間的本質區別是一種數據結構,當它編譯MSIL抖動產生。額外的數據,你不會從本地編譯器。該數據是垃圾收集器所需的,它告訴它如何找回對象根。更多關於this post的數據。不得不遵守這些數據並允許GC完成工作,這使得託管代碼在運行時慢了一點。

+0

很棒的回答。特別是:「CIL並沒有比較好,比如Java JVM中使用的字節碼,它更強大,可以支持任何C++ 03兼容的本機C++代碼。」當我得到一份Java工作時,我看着他們的字節碼規範並且哭了! – hoodaticus

0

Manged C++已棄用。今天要編寫本地C++和Manged代碼,您需要使用C++ \ CLI。它符合CLR,它可以運行其他.net程序集。您還可以使用本地通話,這些都是偉大的interoperabilitybetween本地代碼和.NET代碼 要調用.NET程序集在你的項目給大會增添參考,並添加代碼:

using namespace System; 
+1

我欣賞對C++/CLI的說明。但是,仍然可以將C++/CLI的非託管部分編譯爲本機代碼(非MSIL)。那麼這是如何工作的,因爲代碼的託管部分將被強制編譯爲MSIL? – Everyone

+1

@所有人,文件格式仍然是一個PE文件,並可以包含任何其他的本地代碼(以交叉可移植性爲代價)。的[愈傷組織(https://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.calli(V = vs.110)的.aspx)指令可以用來調用到本機方法。 –

+0

如果您不能將C++/CLI編譯爲本機(僅)。如果你有呼叫託管代碼 –