C 程式設計/標準庫
C 標準庫 是一組標準化的 標頭檔案 和庫例程,用於實現常見的操作,例如輸入/輸出和字元字串處理。與其他語言(例如 COBOL、Fortran 和 PL/I)不同,C 不包含用於這些任務的內建關鍵字,因此幾乎所有 C 程式都依賴於標準庫來執行。
C 程式語言以前沒有提供任何基本函式,例如 I/O 操作。隨著時間的推移,C 使用者社群分享了想法和實現以提供這些函式。這些想法變得普遍,並最終在 1989 年被納入標準化 C 程式語言的定義中。這些現在被稱為 C 標準庫。
Unix 和 C 都是 20 世紀 60 年代後期和 70 年代初期在 AT&T 的貝爾實驗室建立的。在 20 世紀 70 年代,C 程式語言變得越來越流行,許多大學和組織開始為自己的專案建立他們自己的語言變體。到 20 世紀 80 年代初,各種 C 實現之間的相容性問題變得明顯。1983 年,美國國家標準協會 (ANSI) 成立了一個委員會,以制定一個稱為“ANSI C”的 C 標準規範。這項工作最終在 1989 年產生了所謂的 C89 標準。由此產生的標準的一部分是一組軟體庫,稱為 ANSI C 標準庫。
C 標準的後續修訂在庫中添加了幾個新的必需標頭檔案。對這些新擴充套件的支援在不同的實現之間有所不同。
標頭檔案 <iso646.h>、<wchar.h> 和 <wctype.h> 是在 1995 年批准的 C 標準的規範性增補 1(以下簡稱 NA1)中新增的。
標頭檔案 <complex.h>、<fenv.h>、<inttypes.h>、<stdbool.h>、<stdint.h> 和 <tgmath.h> 是在 1999 年釋出的 C 標準修訂版 C99 中新增的。
每個函式的宣告都儲存在標頭檔案中,而函式的實際實現則分離到庫檔案中。標頭檔案的命名和範圍已變得普遍,但庫的組織仍然多種多樣。標準庫通常與編譯器一起提供。由於 C 編譯器通常提供不在 ANSI C 中指定的額外函式,因此特定編譯器的標準庫通常與其他編譯器的標準庫不相容。
事實證明,C 標準庫的許多部分設計得很好。從後視鏡的角度來看,有一些部分被認為是錯誤的。字串輸入函式 gets()(以及使用 scanf() 讀取字串輸入)是許多緩衝區溢位的根源,大多數程式設計指南建議避免使用這種用法。另一個奇怪的地方是 strtok(),它是一個設計為原始 詞法分析器 的函式,但它非常“脆弱”並且難以使用。
ANSI C 標準庫由 24 個 C 標頭檔案組成,可以透過單個指令將這些標頭檔案包含到程式設計師的專案中。每個標頭檔案包含一個或多個函式宣告、資料型別定義和宏。這些標頭檔案的內容如下。
與其他一些語言(例如 Java)相比,標準庫非常小。該庫提供了一組基本的數學函式、字串操作、型別轉換以及基於檔案和控制檯的 I/O。它不包括像 C++ 標準模板庫那樣的“容器型別”的標準集,更不用說完整的圖形使用者介面 (GUI) 工具包、網路工具和 Java 作為標準提供的眾多其他功能。小型標準庫的主要優點是,提供一個工作的 ANSI C 環境比其他語言更容易,因此將 C 移植到新平臺相對容易。
許多其他庫已被開發出來,以提供與其他語言在其標準庫中提供的功能等效的功能。例如,GNOME 桌面環境專案開發了 GTK+ 圖形工具包和 GLib,這是一個容器資料結構庫,還有許多其他著名的例子。可用庫的多樣性意味著一些優秀的工具包在歷史上已經證明了自己的價值。相當大的缺點是它們通常不能很好地協同工作,程式設計師通常熟悉不同的庫集,並且在任何特定平臺上都可能提供不同的庫集。
| <assert.h> | 包含 assert 宏,用於幫助在除錯版本的程式中檢測邏輯錯誤和其他型別的錯誤。 |
| <complex.h> | 一組用於操縱複數的函式。(C99 新增) |
| <ctype.h> | 此標頭檔案包含用於根據字元型別對字元進行分類或在大小寫之間進行轉換的函式,這些函式與使用的字元集無關(通常是 ASCII 或其擴充套件之一,儘管也已知使用 EBCDIC 的實現)。 |
| <errno.h> | 用於測試庫函式報告的錯誤程式碼。 |
| <fenv.h> | 用於控制浮點環境。(C99 新增) |
| <float.h> | 包含定義的常量,指定浮點庫的特定於實現的屬性,例如兩個不同浮點數之間的最小差值 (_EPSILON)、精度最大位數 (_DIG) 以及可以表示的數字範圍 (_MIN、_MAX)。 |
| <inttypes.h> | 用於在整數型別之間進行精確轉換。(C99 新增) |
| <iso646.h> | 用於在 ISO 646 變體字元集中進行程式設計。(NA1 新增) |
| <limits.h> | 包含定義的常量,指定整數型別的特定於實現的屬性,例如可以表示的數字範圍 (_MIN、_MAX)。 |
| <locale.h> | 用於 setlocale() 和相關常量。這用於選擇適當的區域設定。 |
| <math.h> | 用於計算常見的數學函式 -- 有關詳細資訊,請參閱 更多數學 或 C++ 程式設計/程式碼/標準 C 庫/數學。 |
| <setjmp.h> | setjmp 和 longjmp,用於非本地退出 |
| <signal.h> | 用於控制各種異常情況 |
| <stdarg.h> | 用於訪問傳遞給函式的可變數量的引數。 |
| <stdbool.h> | 用於布林資料型別。(C99 新增) |
| <stdint.h> | 用於定義各種整數型別。(C99 新增) |
| <stddef.h> | 用於定義幾個有用的型別和宏。 |
| <stdio.h> | 提供 C 語言的核心輸入和輸出功能。此檔案包括著名的 printf 函式。 |
| <stdlib.h> | 用於執行各種操作,包括轉換、偽隨機數、記憶體分配、程序控制、環境、訊號、搜尋和排序。 |
| <string.h> | 用於操作幾種型別的字串。 |
| <tgmath.h> | 用於型別通用數學函式。(C99 新增) |
| <time.h> | 用於在各種時間和日期格式之間進行轉換。 |
| <wchar.h> | 用於使用寬字元操作寬流和幾種型別的字串 - 支援多種語言的關鍵。(NA1 新增) |
| <wctype.h> | 用於對寬字元進行分類。 (NA1 中新增) |
常用支援庫
[edit | edit source]雖然沒有標準化,但 C 程式可能依賴於包含編譯器在執行時使用的程式碼的執行時庫例程。 例如,在呼叫 main() 之前初始化作業系統程序的程式碼是在給定供應商的編譯器的 C 執行時庫中實現的。 執行時庫程式碼可能有助於其他語言功能的實現,例如處理未捕獲的異常或實現浮點程式碼。
C 標準庫只記錄本文中提到的特定例程的可用性和行為方式。 由於編譯器實現可能依賴於這些額外的實現級函式的可用性,因此供應商特定的例程很可能與 C 標準庫打包在同一個模組中,因為它們都可能被使用其工具集構建的任何程式使用。
雖然由於這種打包方式,C 執行時庫經常與 C 標準庫混淆,但 C 執行時庫不是語言的標準化部分,它是供應商特定的。
編譯器內建函式
[edit | edit source]一些編譯器(例如,GCC)提供了許多 C 標準庫函式的內建版本; 也就是說,函式的實現被寫入編譯後的目標檔案,程式呼叫內建版本而不是 C 庫共享目標檔案中的函式。 這減少了函式呼叫開銷,尤其是在函式呼叫被替換為內聯變體的情況下,並允許其他形式的最佳化(因為編譯器知道內建變體的控制流特性),但可能會在除錯時造成混淆(例如,內建版本無法被替換為檢測變體)。
POSIX 標準庫
[edit | edit source]POSIX(以及 Single Unix Specification)指定了一些例程,這些例程應該在 C 標準庫本身之外提供; 這些例程通常與 C 標準庫函式一起實現,其緊密程度各不相同。 例如,glibc 在 libc.so 中實現 fork 等函式,但在 NPTL 合併到 glibc 之前,它是一個單獨的庫,有自己的連結器標誌。 通常,這種 POSIX 指定的函式將被視為庫的一部分; C 庫本身可能會被標識為 ANSI 或 ISO C 庫。
以下庫由 POSIX 識別
| c |
此選項應提供 POSIX.1-2008 的系統介面卷中引用的所有介面,除了那些被列為駐留在 <aio.h>、<arpa/inet.h>、<complex.h>、<fenv.h>、<math.h>、<mqueue.h>、<netdb.h>、<net/if.h>、<netinet/in.h>、<pthread.h>、<sched.h>、<semaphore.h>、<spawn.h>、<sys/socket.h>、<signal.h> 中的 pthread_kill() 和 pthread_sigmask()、<trace.h>、<sys/mman.h> 中標記為可選的介面、<fcntl.h> 中標記為 ADV(諮詢資訊)的介面,以及以 clock_ 或 time_ 為字首的介面在 <time.h> 中。 此選項不必存在以導致搜尋此庫。 |
| l |
此選項應提供 lex 的 C 語言輸出所需的所有介面,這些介面不是透過 -l c 選項提供的。 (flex 程式,一個 lex 的克隆,使用 fl 而不是 l。) |
| pthread |
此選項應提供 <pthread.h> 中引用的所有介面,以及 <signal.h> 中引用的 pthread_kill() 和 pthread_sigmask()。 實現可能在沒有此選項的情況下搜尋此庫。 |
| m |
此選項應提供 <math.h>、<complex.h> 和 <fenv.h> 中引用的所有介面。 實現可能在沒有此選項的情況下搜尋此庫。 |
| rt |
此選項應提供 <aio.h>、<mqueue.h>、<sched.h>、<semaphore.h> 和 <spawn.h> 中引用的所有介面,<sys/mman.h> 中標記為可選的介面,<fcntl.h> 中標記為 ADV(諮詢資訊)的介面,以及 <time.h> 中以 clock_ 和 time_ 為字首的介面。 實現可能在沒有此選項的情況下搜尋此庫。 |
| trace |
此選項應提供 <trace.h> 中引用的所有介面。 實現可能在沒有此選項的情況下搜尋此庫。 |
| xnet |
此選項應提供 <arpa/inet.h>、<netdb.h>、<net/if.h>、<netinet/in.h> 和 <sys/socket.h> 中引用的所有介面。 實現可能在沒有此選項的情況下搜尋此庫。 |
| y |
此選項應提供 yacc 的 C 語言輸出所需的所有介面,這些介面不是透過 -l c 選項提供的。 (yacc 的一些克隆,包括 bison 和 byacc,在生成的檔案中包含整個庫,因此無需使用 -l y。) |