C_(programming_language)

**C** 是一種通用的、程序式編程程式語言，支援結構化編程、詞法作用域和遞迴，使用靜態型別系統，並且廣泛用於系統軟體與應用軟體的開發。

C 語言於 1969 年至 1973 年間，為了移植與開發 UNIX 作業系統，由丹尼斯・里奇與肯・湯普遜，以 B 語言為基礎，在貝爾實驗室設計、開發出來。二十世紀八十年代，C 語言應用日漸廣泛。為了避免各開發廠商用的 C 語言的語法產生差異，美國國家標準局為 C 語言訂定了一套完整的國際標準語法，稱為 ANSI C，作為 C 語言的標準。與此同時，國際標準化組織也接受該標準為國際標準。因此，ANSI C 也同時被稱為 ISO C。二十世紀八十年代至今的有關程式開發工具，一般都支援符合 ANSI C 的語法。

C 語言具有高效、靈活、功能豐富、表達力強和較高的可移植性等特點，在程式設計中備受青睞，成為最近 25 年使用最為廣泛的程式語言。目前，C 語言編譯器普遍存在於各種不同的作業系統中，例如 Microsoft Windows、macOS、Linux、Unix 等。C 語言的設計影響了眾多後來的程式語言，例如 C++、Objective-C、Java、C# 等。現行的許多軟體都是由 C 語言或者其影響和衍生的程式語言開發出來的。

## 概述

與 ALGOL 一族的大多數程序式程式語言類似，C 語言是一個有結構化程式設計、具有變數作用域（variable scope）以及遞迴功能的程序式語言。其採用的靜態型別系統可以防止無意的程式設計操作。C 語言中所有的可執行代碼都被包含在子程式（函式）里。其傳遞參數均是以值傳遞（pass by value），另外也可以傳遞指標（a pointer passed by value）。C 語言是自由形式語言，即其原始碼的縮排並不影響程式的功能，而是使用分號作為語句的結尾，花括號來表示代碼塊。

由於 C 語言的語言規模較小，若干高層的機制需要使用定義的函式來提供。比如，C 語言並沒有直接處理複合物件（例如字串、集合、列表、陣列等）的操作，也沒有對於記憶體分配工具和記憶體回收工具的直接定義，同時也本身不具有輸入和輸出以及檔案存取的方法。然而，使用者定義的函式和 C 語言標準庫中的函式為這些高層的機制提供了可能性。

C 語言也具有以下的特性：

* 基本資料類型包括字元、整型和浮點數等。另外也有衍生的各種資料類型，如指標、陣列、結構和聯合。
* 部份的變數類型可以轉換，例如整數型和字元型變數。
* 透過指標（pointer），C 語言可以容易的對記憶體進行低階控制。
* 不同的變數類型可以用結構體（struct）組合在一起。
* 具有基本的控制流：語句組、條件判斷、多路選擇、迴圈等。
* 函式可以返回各種資料類型的值，並且都可以遞迴呼叫。每次呼叫函式會重新建立變數。
* C 語言只有 32 個保留字（reserved keywords），使變數、函式命名有更多彈性。
* 編譯預處理（preprocessor）讓 C 語言的編譯更具有彈性。

## 歷史

20 世紀 70 年代，肯・湯姆森為了使其設計的 Unix 系統更加高效，使用 B 語言的變種（即 C 語言）在 DEC PDP-7 電腦上重寫了 Unix。C 語言中許多重要概念來源於 BCPL 語言，其對 C 語言的影響也間接地來源於 B 語言。在 1978 年，丹尼斯・里奇和布萊恩・柯林漢合作出版了《C 程式設計語言》第一版，事實上即為 K&R C 標準。1983 年，為了制定一個獨立於具體機器且無歧義的 C 語言標準，美國國家標準協會成立了一個委員會，並在 1988 年完成了該標準的制定，即 ANSI C。此標準同時被國際標準化組織所採納，也被稱作 ISO C。

其後，C 語言至今經歷了幾次標準更新，誕生了 C99、C11 和目前最新的標準 C18。C 語言標準的下一次更新 C2x 目前正在起草中。

## 語法

C 語言的形式文法由國際標準化組織所制定。C 語言的原始碼包含聲明和函式定義。函式定義又包含聲明和語句。聲明可以定義一個新的類型，比如結構（`struct`）、聯合（`union`）和列舉（`enum`），也可以為變數賦予類型和預留記憶體。複合語句由一對花括號包含，可以使得幾個語句從文法上變成一個語句。

作為一種指令式編程語言，C 語言使用語句執行操作。最常見的語句是運算式語句，由一個運算式後加一個分號組成，可以令系統呼叫函式和為變數賦值。C 語言也提供各種用保留關鍵字組成的控制流語句，以達到結構化編程的效果，例如選擇語句（`if` 和 `else`）、迴圈語句（`for` 迴圈、`while` 迴圈和 `do`...`while` 迴圈）和跳轉語句（`goto`、`break` 和 `continue`）。運算式可以包含不同的運算子，也可以呼叫函式。

## Hello World 程式

現在廣泛被編程初學者使用的 "hello, world" 程式實例最初就是出現在《C 程式設計語言》第一版中。下面是一個在標準輸出裝置（stdout）上列印出 "Hello, world!" 字串的簡單程式。類似的程式，通常作為初學程式語言時的第一個程式：

其中只有 int，void，return 為 C 語言的關鍵字，前置處理器會將 `#include <stdio.h>` 替換為 stdio.h 檔案的內容。

main 函式是 C 語言程式的入口點。

`"Hello, world!\n"` 中的 `\n` 是一個跳脫字元，形式為 `\` 加上一個字元。所起的作用在 ASCII 碼中規定。

printf 是聲明於 stdio.h 的函式，關於 printf 的更多細節，參見 printf；

關于格式化字串的更多資訊，參見格式化字串。

## 記憶體管理

C 語言的特色之一是：程式設計師必須親自處理記憶體的分配細節。語言不負責記憶體邊界檢查，這是因為在執行時進行記憶體邊界檢查會造成效能問題，與 UNIX 哲學不符。此特性容易導致緩衝區溢位問題。然而，部分編譯器（如英特爾編譯器）會出於安全性的考量，提供方法以進行執行時記憶體邊界檢查。

大多數 C 語言實現使用棧（Stack）來儲存函式返回位址／堆疊框基址、完成函式的參數傳遞和函式局部變數的儲存。然而，在部分極特殊的平台上，使用棧並不能獲得最大效率。此時的實現由編譯器決定。
如果程式需要在執行的過程中動態分配記憶體，可以利用堆（Heap）來實現。

基本上 C 程式的元素儲存在記憶體的時候有 3 種分配策略：

* 靜態分配

如果一個變數聲明為全域變數或者是函式的靜態變數，這個變數的儲存將使用靜態分配方式。靜態分配的記憶體一般會被編譯器放在資料段或代碼段來儲存，具體取決於實現。這樣做的前提是，在**編譯時**就必須確定變數的大小。
以 IA32 的 x86 平台及 gcc 編譯器為例，全域及靜態變數放在資料段的低階；全域及靜態常數放在代碼段的高端。

* 自動分配

函式的自動局部變數應該隨著函式的返回會自動釋放（失效），這個要求在一般的體系中都是利用棧（Stack）來滿足的。相比於靜態分配，這時候，就不必絕對要求這個變數在**編譯時**就必須確定變數的大小，**執行時**才決定也不遲，但是 C89 仍然要求在**編譯時**就要確定，而 C99 放鬆了這個限制。但無論是 C89 還是 C99，都不允許一個已經分配的自動變數執行時改變大小。

所以說 **C 函式永遠不應該返回一個局部變數的位址**。

要指出的是，自動分配也屬於動態分配，甚至可以用 alloca 函式來像分配堆（Heap）一樣進行分配，而且釋放是自動的。

* 動態分配

還有一種更加特殊的情況，變數的大小在執行時有可能改變，或者雖然單個變數大小不變，變數的數目卻有很大彈性，不能靜態分配或者自動分配，這時候可以使用堆（Heap）來滿足要求。ANSI C 定義的堆操作函式是 malloc、calloc、realloc 和 free。

使用堆（Heap）記憶體將帶來額外的開銷和風險。

## 庫

C 語言的標準文件要求了一個平台移植 C 語言的時候至少要實現的一些功能和封裝的集合，稱為「標準庫」，標準庫的聲明頭部通過前置處理器命令 #include 進行參照。

在 C89 標準中：

在 94 年的修正版中

* <iso646.h>

* <wchar.h>

* <wctype.h>

在 C99 中增加了六個函式庫

* <complex.h>

* <fenv.h>

* <inttypes.h>

* <stdbool.h>

* <stdint.h>

* <tgmath.h>

以上是 C 語言的標準。各個系統各自又對 C 庫函式進行的各種擴充，就浩如煙海了。如 POSIX C、GNU C 等。

## 工具軟體

工具軟體可以幫助程式設計者避免一些程式中潛藏或容易出現的問題，例如常會造成程式未預期動作或是執行期錯誤的程式碼。

許多語言都有自動原始碼檢查及審計工具，C 語言也有類似工具，像是 Lint。可以在程式剛寫好時用 Lint 找出可能有問題的程式，通過 Lint 後再用 C 編譯器進行編譯，許多編譯器也可以設定是否要針對一些可能有問題的程式碼提出警告。MISRA C 是一套針對嵌入式系統的法則，可主要也是避免一些可能有問題的程式碼。

也有一些編譯器、程式庫或作業系統可以處理一些非標準 C 語言的功能，例如邊界值檢查、緩衝區溢位偵測、序列化及自動垃圾回收功能。

使用像 Valgrind 或 IBM Rational Purify 等軟體工具，或者連結有特別 malloc 函式的程式庫，有助於找出一些運行期記憶體使用的問題。

## 經典錯誤

「void main ()」的用法並不是任何標準制定的。 C 語言標準語法是「int main ()」，任何實現都必須支援 `int main(void) { /* ... */ }` 和 `int main(int argc, char* argv[]) { /* ... */ }`。 在 C++ 標準中，main 的標準型態應是 int，否則類型是由實現定義的。任何實現都必須支援 `int main() { /* ... */ }` 和 `int main(int argc, char* argv[]) { /* ... */ }`。

## 參見

* 塊 (C 語言擴充)

## 註腳

### 註解

### 參考資料

## 參考資料

## 外部連結

* Coding Programmer Page / C Library Reference and Examples（頁面存檔備份，存於網際網路檔案館） (english)
* GCC 首頁（頁面存檔備份，存於網際網路檔案館）
* GLIBC2 首頁（頁面存檔備份，存於網際網路檔案館）
* Visual Studio Express 首頁（頁面存檔備份，存於網際網路檔案館）
* ISO/IEC 9899（頁面存檔備份，存於網際網路檔案館）。C99 標準的官方網站。目前（2020 年）可直接下載的標準文字是 ISO/IEC 9899:202x（頁面存檔備份，存於網際網路檔案館）。