08.14 C和C++遠比你想象中的複雜和恐怖,關於C和C++標準庫的一些事兒

什麼是 C 和 C ++ 標準庫?

C和C++遠比你想象中的複雜和恐怖,關於C和C++標準庫的一些事兒

C/C++學習資料,請私信我“代碼”,即可獲取

簡要介紹編寫C/C ++應用程序的領域,標準庫的作用以及它是如何在各種操作系統中實現的。

我已經接觸C++一段時間了,一開始就讓我感到疑惑的是其內部結構:我所使用的內核函數和類從何而來? 誰發明了它們? 他們是打包在我係統中的某個地方嗎? 是否存在一份官方的C ++手冊?

在本文中,我將通過從C和C ++語言的本質到實際實現來嘗試回答這些問題。

C和C++是你所看到版本問題

當我們談論C和C++時,實際上是指一組定義(程序)語言應該做些什麼,如何表現,應該提供哪些功能的規則。C/C++的編譯器為了處理C/C++編寫的源代碼必須跟隨著這些規則,並生成二進制應用程序。聽起來非常接近於HTML:瀏覽器遵循著一組指令,所以它們可以以明確的方式來渲染網頁。

與HTML一樣,C和C++的規則都是理論上的。國際標準化組織(ISO)的一大群人每年都會聚集幾次來討論和定義語言規則。沒錯,C和C++是標準化的東西。他們最終都會得到一本官方的叫標準的書,你可以從他們的網站中購買。隨著語言的發展新的papers(指官方的叫標準的書)會被髮布,每一次都定義一個新的標準。這就是為什麼我們會有不同的C和C++版本的原因:C99, C11, C++03, C++11, C++14等等,數字與出版/發佈年份相符。

C和C++遠比你想象中的複雜和恐怖,關於C和C++標準庫的一些事兒

C/C++學習資料,請私信我“代碼”,即可獲取

C標準庫

C標準庫也稱為ISO C庫,是用於完成諸如輸入/輸出處理、字符串處理、內存管理、數學計算和許多其他操作系統服務等任務的宏、類型和函數的集合。它是在C標準中(例如C11標準)中定義的。其內容分佈在不同的頭文件中,比如上面我所提到的math.h。

C++標準庫

和C標準庫的概念類似,但僅針對C ++。C++標準庫是一組C++模板類,它提供了通用的編程數據結構和函數,如鏈表、堆、數組、算法、迭代器和任何其他你可以想到的C++組件。C ++標準庫也包含了C標準庫,並在C++標準中進行了定義(例如C++ 11標準)。

C/C++標準庫的實現

我們從這裡開始討論真正的代碼了。從事於標準庫實現的開發者閱讀官方的ISO規範並將其轉化為代碼。他們必須依賴其操作系統所提供的功能(讀/寫文件,分配內存,創建線程,......所有這些被稱為系統調用),因此每個平臺都有其自己的標準庫實現。 有時它是系統內核的一部分,有時它是作為一個附加組件 - 編譯器 - 必須單獨下載。

GNU/Linux版實現

C和C++遠比你想象中的複雜和恐怖,關於C和C++標準庫的一些事兒

C/C++學習資料,請私信我“代碼”,即可獲取

GNU C庫,也稱為glibc, 是C標準庫的GNU項目實現。並非所有的標準C函數都可以在glibc中找到:大多數數學函數實際上是在libm庫中實現的,這是一個獨立的庫。

截至今天,glibc是Linux上使用最廣泛的C庫。 然而,在90年代期間,有一段時間裡,glibc有一個競爭對手稱為Linux libc(或者簡稱libc),它是由glibc 1.x的一個分支產生的。在一段時間裡,Linux libc是許多Linux發行版中的標準C庫。

經過多年的發展,glibc竟然比Linux libc更具優勢,並且所有使用它的Linux發行版都切換回了glibc。所以,如果你在你的磁盤中找到一個名為libc.so.6的文件,請不要擔心:它是現代版的glibc。為了避免與之前的Linux libc版本混淆,版本號增加到了6(他們無法將其命名為glibc.so.6:所有Linux庫都必須以lib前綴打頭)。

另一方面,C++標準庫的實現位於libstdc++或GNU標準C++庫中。這是一個正在進行的在GNU/Linux上實現標準C++庫的項目。一般來說,所有常規的Linux發行版都默認使用libstdc++。

Mac和iOS版實現

C和C++遠比你想象中的複雜和恐怖,關於C和C++標準庫的一些事兒

C/C++學習資料,請私信我“代碼”,即可獲取

在Mac和iOS上,C標準庫的實現是libSystem的一部分,libSystem是位於/usr/lib/libSystem.dylib中的核心庫。LibSystem包含其他組件,如數學庫、線程庫和其他底層實用程序。

關於C++標準庫,在OS X Mavericks(V10.9)之前的Mac上,libstdc++是默認選項。這在現代的基於Linux的系統上可以找到的同樣的實現。自OS X Mavericks開始,Apple切換到使用libc++,這是LLVM項目——Mac官方編譯器框架——所引入的GNU libstdc++標準庫的替代。

IOS開發者可以使用iOS SDK(軟件開發工具包)來訪問標準庫,它是一系列允許創建移動應用程序的工具。

Windows版實現

C和C++遠比你想象中的複雜和恐怖,關於C和C++標準庫的一些事兒

C/C++學習資料,請私信我“代碼”,即可獲取

在Windows上,標準庫的實現一直嚴格限定在Visual Studio中,它是微軟官方的編譯器。他們通常稱之為C/C++運行時庫(CRT),並且它涵蓋了c/c++二者的實現。

在最開始,CRT被實現為CRTDLL.DLL庫(我猜,當時沒有可用的C++標準庫)。從Windows 95開始,Microsoft開始將其遷移到MSVCRT [版本號] .DLL(MSVCR20.DLL,MSVCR70.DLL等)之上,據推測也包含C++標準庫。在1997年左近,他們決定將文件名簡化為MSVCRT.DLL,這不幸導致了令人討厭的DLL混亂。這就是為什麼從Visual Studio 7.0版開始,他們切換回每個版本使用單獨的DLL了。

Visual Studio 2015引入了深度的CRT重構。C/C ++標準庫的實現遷移到一個新庫,Universal C運行時庫 (Universal CRT或UCRT),編譯為UCRTBASE.DLL。 UCRT目前已經成為Windows組之一,從Windows 10開始作為操作系統的一部分提供。

Android版實現

C和C++遠比你想象中的複雜和恐怖,關於C和C++標準庫的一些事兒

C/C++學習資料,請私信我“代碼”,即可獲取

Bionic是Google為其Android操作系統所編寫的C標準庫實現,它直接在底層使用。 第三方開發者可以通過Android原生開發工具包(NDK)訪問Bionic,該工具集允許你使用C和C++代碼編寫Android應用程序。

在 C++ 端, NDK提供了很多版本的實現:

  • libc++,從從Lollipop開始的官方安卓系統和現代Mac操作系統都將其作為C++標準庫使用。從NDK發佈17版本開始,它將成為NDK中唯一可用的C++標準庫實現;
  • gnustl,libstdc++的別名,這兩者在GNU/linux是同一個庫。這個庫的已被棄用,它將在NDK發佈18中刪除;
  • STLport,由STLport項目編寫的C++標準庫的第三方實現,自2008年以來一直處於不活躍狀態。與gnustl一樣,STLport將在NDK發佈18中移除。

我能使用不同版本的實現代碼來替代默認實現嗎?

如果你正在使用資源非常有限的系統,則通常需要引用C標準庫的不同實現。比如,uClibc-ng, musl libc和diet libc等等,所有這些都適用於嵌入式Linux系統的開發,提供更小的二進制文件和更少的內存佔用。

C++標準庫也有不同的實現版本:Apache C++標準庫,uSTL以及EASTL等等。後面兩個實際上僅關注模板部分,而不是完整的庫,並且他們是在速度優先的情況下開發的。Apache版本的庫注重的是可移植性。

如果我們脫離了標準庫怎麼辦?

C和C++遠比你想象中的複雜和恐怖,關於C和C++標準庫的一些事兒

不使用標準庫很簡單:只要在你的程序中不引入它們的任何一個頭文件,你的工作就完成了。然而,為了讓這個操作更有意義一些,你需要通過一些提供的系統調用使用某種方法與操作系統互動。就像我之前說的,這就是標準庫中的函數/方法在底層實現的時候所使用的。很可能你也會不得不調用這些方法來與硬件設備交互。

如果對你來說這聽起來很讓人激動,有些人已經開始在網上嘗試在不導入標準庫的情況下創建工作流程。因為你依賴於一個特定操作系統所提供的函數,這種方式會喪失可移植性。然而通過使用這種艱難的方式,肯會讓你學到更多,而且讓你更好的理解當你所做的事情,即使是在使用高級庫的時候。

除了知識,當你在嵌入式操作系統上面工作的時候你不會想去引入標準庫:因為代碼不需要移植,在有限的內存中每個字節都很重要,這會讓你更加精準的寫代碼。另一個使用背景就是demoscene,在這裡人們儘量有限的程序的二進制大小中去保留高質量的音視頻——4K仍然不是最小值:一些demoparties使用1K,256字節,64字節或者甚至32字節來競爭。在那裡不允許使用標準庫!

C/C++更多精彩


分享到:


相關文章: