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

oschina發表於2018-08-22

  簡要介紹編寫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等等,數字與出版/釋出年份相符。

  這些標準都市非常詳細和有技術新的文件:我不會把它們當作手冊。通常會分為兩部分:

  1.C/C++的功能和特性;

  2.C/C++的API--開發人員可以用於他們的C/C++程式的一個類、函式和巨集的集合。它也被稱為標準庫。

  例如,這裡有個來自於C標準庫第一部分的摘選,它定義了main函式的結構:

  1.main的定義,程式啟動時呼叫的函式。

  這是另外一個來自與同樣標準的摘錄,描述了CAPI的成員--fmin函式:

  2.在math.h偷檔案中定義min函式。

  如你所見,幾乎沒涉及到程式碼。有人必須閱讀標準並將其轉換成計算機可以消化的東西。這是工作於編譯器和(功能)實現上人們所做的:前者是一種可以讀取和處理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版實現

  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版實現

  在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版實現

  在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版實現

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

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

  • libc++,從從Lollipop開始的官方安卓系統和現代Mac作業系統都將其作為C++標準庫使用從NDK釋出17版本開始,它將成為NDK中唯一可用的C++標準庫實現

  • gnustllibstdc++的別名,這兩者在GNU/linux是同一個庫。這個庫的已被棄用,它將在NDK釋出18中刪除

  • STLport由STLport專案編寫的C++標準庫的第三方實現,自2008年以來一直處於不活躍狀態。與gnustl一樣,STLport將在NDK釋出18中移除。

  我能使用不同版本的實現程式碼來替代預設實現嗎?

  如果你正在使用資源非常有限的系統,則通常需要引用C標準庫的不同實現。比如,uClibc-ngmusl libcdiet libc等等,所有這些都適用於嵌入式Linux系統的開發,提供更小的二進位制檔案和更少的記憶體佔用。

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

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

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

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

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

  原文地址:https://www.internalpointers.com/post/c-c-standard-library

相關文章