C 語言和 C 的關係相當密切，但是也存在許多顯著的差異。C 標準起源於早期 C 標準， 並被設計為與當時的 C 語言在原始碼編寫和連結方面很大程度上相容。 因此，兩種語言的開發工具（例如 IDE 和編譯器）通常被整合到單個產品中，程式設計師可以自己選擇編寫的是 C 還是 C，開發工具通常會根據程式設計師的選擇使用不同的編譯器和連結器或不同的庫。 但是，C 並不是 C 的子集， 一般的 C 程式碼不經修改很難被一些嚴格符合 C 標準的 C 編譯器成功編譯；同樣，C 引入了許多 C 中沒有的特性，所以，幾乎所有用 C 編寫的程式碼都無法被 C 編譯器成功編譯。在這篇文章中，我們主要討論的是它們在公共部分的差異，比如在 C 語言中合法的程式碼到了 C 中成為了不合法的程式碼，或一段程式碼在 C 和 C 中表現出不同的行為。 C 的創始人 Bjarne Stroustrup 建議 C 和 C 應該儘可能減小差異，以最大限度地提高這兩種語言的相容性；而另一些人則認為 C 和 C 畢竟是兩種不同的語言 雖然 C 起源於 C 因此它們之間的相容性並不是那麼重要。 而 ANSI 是這樣看的：「我們贊同保持 C 與 C 的最大公共子集原則」，同時「保持它們的差別，使這兩種語言繼續獨立發展」，「 委員會希望 C 成為重要的和強有力的語言。」Rationale for International StandardProgramming LanguagesC revision 510 200304 截止到 C20 和 C2x，C 還是不支援部分 C 語言特性，如變長陣列，原生複數支援和 restrict 型別修飾符。另一方面，與 C89 相比，C99 透過合併 C 功能（例如 註釋，允許宣告出現在程式碼中而不只是在函式頭）減少了一些其他不相容性。 在 C 中允許而在 C 中不允許存在的程式碼語句 C 較 C 語言有更嚴格的型別轉換和初始化規則 It is invalid to jump past a declaration with explicit or implicit initializer except across entire block not entered With this simple compiletime rule C assures that if an initialized variable is in scope then it has assuredly been initialized ， 因此一些在 C 語言裡合法的語句在 C 裡是不合法的。ISO C 附錄 C1 中列出了這些區別。 一個常見的區別是在 C 語言中的指標型別更加弱型別。具體來說，C 語言允許將 void 指標賦值給任何型別的指標而無需強制轉換，而 C 則不允許；這個習慣用法經常出現在使用 malloc 管理記憶體的 C 程式碼中， 或 POSIX 執行緒庫的上下文傳遞以及其他涉及回撥的框架。例如，下面這個例子在 C 語言中是可行的，但在 C 中不允許 void ptr 從 void 到 int 的隱式轉換 int i ptr 或類似的： int j malloc 5 sizeof j 從 void 到 int 的隱式轉換 為了使程式碼在 C 和 C 中同時可用， 必須使用強制型別轉換， 如下所示（然而這樣在兩種語言中都會報警告）： void ptr int i int ptr int j int malloc 5 sizeof j C 中提供了其它方法來實現指標型別轉換。C 不推薦繼續使用老式型別轉換。老式型別轉換在形式上來說不是特別清晰，容易被忽略。。 void ptr auto i reinterpret_castint ptr auto j new int 5 C 語言允許在安全的前提下隱式新增除 const 和 volatile 的關鍵字，而 C 則不會。 C 為 C 語言的部分函式添加了一個引數帶 const 的過載，例如 strchr 在 C 語言中的宣告為，而在 C 中則有一個過載函式為 const char strchr const char 。 C 在列舉方面也更加嚴格。在 C 中，int 不能被隱式轉換為列舉型別。因為在 C 標準中並沒有規定列舉的型別為 int（在 C 語言標準中則規定了），並且大小可能與 C 中 int 的大小不同。從 C11 開始，C 允許程式設計師將自定義的整數型別賦值給列舉型別。 在 C 中，const 變數必須被初始化，但在 C 語言中不必： const int var1 const int var2 1 第一行程式碼在 C 語言中是允許的（在某些編譯器中可能會報告 Warning），但在 C 中會報錯；第二行程式碼在 C 和 C 中都是合法的。 C 不允許和標籤之間出現初始化語句。如下示例所示，該段程式碼在 C 語言中是允許的，但在 C 中不允許。 void fn void goto flack int i 1 flack 雖然語法上有效，但如果跳過的堆疊幀包含具有非平凡（nontrivial）解構函式的物件（即指標），則函式會在 C 中被認為是未定義的操作。 C 可以自由定義此時的行為，以便能夠呼叫解構函式。但是，這樣會使的一些用法失效， 否則就可以透過在單獨的呼叫堆疊之間進行 longjmp 來實現執行緒或協程 在全域性地址空間中從較低的呼叫堆疊跳轉到較高的呼叫堆疊時，將解構函式用於較低呼叫堆疊中的每個物件。這個問題在 C 語言中不存在。 C 語言中允許使用與用，和型別名稱相同的名稱定義新結構體。 enum BOOL FALSE TRUE typedef int BOOL 在 C 語言中允許，在 C 中不允許 在 C 語言中，由，或建立的型別在宣告變數時必須在自定義的型別前加，或（取決於定義時的型別），而在 C 中不必。因為自定義型別在建立時已隱含 typedef（這也是上一點區別形成的原因）。 struct foo int bar 在 C 中，以上形式被隱式轉換為： typedef struct foo int bar foo struct foo foobar 在 C 與 C 中均可 foo foobar2 在 C 語言中不允許，在 C 中允許 在 C 中不允許使用舊式 KR 宣告（如下所示），這種宣告在 C 語言中仍然可用，但是標準已將這種宣告方式列為「過時」（「過時」是在 ISO C 標準中定義的術語，它表示委員會可以考慮在未來的標準中將其刪除）。 int add ab int a int b return ab 在 C99 標準出現之前，C 語言允許隱式函式宣告（即省略函式宣告），而 C 不允許；但在 C99 標準出現及以後，C 與 C 均不允許使用這種形式。 在 C 語言中，如果函式原型中沒有引數（如，表明該函式的引數不確定（這是一種標準不推薦的用法）；而在 C 中相同的形式等同於。如果想要在 C 語言中表示沒有引數，應該使用。 在 C 和 C 中，都可以巢狀定義 struct 型別，如下所示： struct foo struct bar int x int y 然而，在使用時，C 和 C 採用不同的方法，假設此時已有 struct foo 型別變數 a， 且 x 1，y 2；如要將 x 賦值給變數 b，c： 以下是 C 語言方法，在 C 中不允許： int b ax 以下是 C 特有方法，在 C 中不允許 int c ax C99 和 C11 添加了一些未包含在標準 C 中的附加功能，例如複數，變長陣列（值得注意的是，在 C99 中列為強制要求的 VLA（變長陣列）和複數在 C11 中被列為了可選項，這是由於部分特殊平臺的 C 編譯器無法有效率地實現或無法實現這兩個功能導致的。目前基本所有平臺都有對應的可使用 VLA 的編譯器），靈活陣列型別（Flexible array member，也叫伸縮型陣列成員），關鍵字，陣列引數限定詞，，指定初始化專案，可變引數宏，附加數學庫，預定義的識別符號（如__func__ 和可移植整數型別。 C99 中透過內建的關鍵字_Complex 和由它定義的宏 complex 實現了虛數型別 float complex 和 double complex；而 C 透過一種完全不同的方式實現了它 使用虛數庫。這兩種方式是不相容的。 VLA 可能導致 sizeof 的值在執行時才能確定。 void foo size_t x int a 使用 VLA 的函式 void foo size_t x int a x printf zun sizeof a 等同於 sizeof int char s x2 printf zun sizeof s 將顯示 x2 在 C99 中，如果一個結構體有多個變數且它的最後一個變數為陣列，則它可以是一個柔性陣列。它與 VLA 類似，但 VLA 不能出現在定義中。它不指定陣列的長度。截止到 C20，C 中沒有類似的功能。下面是它的一個例子： struct X int n m char bytes 截止到 C20 標準，restrict 型別限定符並沒有出現在 C 裡；但是很多編譯器都提供了對它的支援（如 GCC，MSVC，ICC，Clang 等）。 函式宣告中的陣列型別限定符在 C 中是不允許的，下面是一個例子： int foo int a const 相當於 int foo int const a int bar char s static 5 表示 s 的長度至少為 5 C 中的複合文字特性在 C 中以一種叫做 列表初始化 的方法被實現 雖然它們在意義和作用上是不同的，但它們通常能起到相同的效果。 struct X a struct X4 6 在 C 中等於 X 4 6 從 C99 開始，C 語言支援結構的指定值初始化；在 C20 以前，這是不允許的；但是從 C20 標準開始，C 也支援了這個特性。 struct X a n 4 m 6 char s 20 0 a 8g 在 C 中，可以使用 noreturn 來標記一個沒有返回值的函式，但在 C11 以前沒有這樣一個關鍵字。在 C11 中新增了關鍵字 _Noreturn。 C 語言允許在函式原型中聲明覆合數據型別，而 C 不允許。 C 較 C 語言增加了一些關鍵字，這使得如果一段 C 語言程式碼使用了 C 中新增的關鍵字作為識別符號，它將會是非法的。 struct template int new struct template class 以上程式碼在 C 語言中是允許的，但是在 C 中不允許。 在 C 和 C 中行為不同的語句 有一些語句在 C 和 C 中都有效，但是在兩種語言中會產生不同的結果。 char 型別在 C 語言中的大小等於 int 型別的大小，而在 C 中的大小就是 char 型別的大小，即 1 位元組。因此當有語句時，在 C 語言中的結果等於，在 C 中的結果為 1。而且這種差異導致在 C 語言中，無論宣告形式為還是，其所宣告的都是一個有符號表達式，而在 C 中，這取決於實現。 在 C 中，一個 const 變數除非被顯式宣告為 extern，否則這個變數將為內部連結，這與 C extern 語言預設變數作用域為檔案不同。實際上，這不會導致相同的 C 和 C 程式碼產生不同的結果，而是會導致編譯時或連結錯誤。 在 C 語言中，如果不希望在一個檔案中連結到一個不再此檔案中的行內函數，則必須在函式宣告中加 extern；而 C 則會自動處理這些問題。更詳細地，C 語言有兩種 inline 函式定義：普通的外部定義（即顯式新增 extern）和內聯版本。另一方面，C 僅為行內函數提供內聯定義。在 C 語言中，內聯定義與 static 定義類似，因為它可以與其他檔案中有檔案作用域的同名函式或同一翻譯單元中任意數量的相同名稱的內聯或普通函式共存，這是合法的。當這些函式對編譯器可見時，C 編譯器會選擇一個函式（這取決於實現）。而在 C 中，若一個 inline 函式具有外部作用域，則它在所有檔案中的宣告都必須相同。最後，靜態行內函數在 C 和 C 中的行為相同。 C 和 C 中都有布林型別，但是它們有不同的定義。在 C 中，，，作為內建型別關鍵字提供，在實現時，true 和 false 為 bool 型別。而在 C99 以前，C 語言中沒有布林型別；C99 提供了關鍵字型別，但沒有 true，false 關鍵字。為了增加與 C 的相容性，C99 提供了標頭檔案，其中一部分程式碼如下（選自 GCC 編譯器，著作權資訊在註釋中）： Copyright C 19982020 Free Software Foundation Inc This file is part of GCC GCC is free software you can redistribute it andor modify it under the terms of the GNU General Public License as published by the Free Software Foundation either version 3 or at your option any later version GCC is distributed in the hope that it will be useful but WITHOUT ANY WARRANTY without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License for more details Under Section 7 of GPL version 3 you are granted additional permissions described in the GCC Runtime Library Exception version 31 as published by the Free Software Foundation You should have received a copy of the GNU General Public License and a copy of the GCC Runtime Library Exception along with this program see the files COPYING3 and COPYINGRUNTIME respectively If not see httpwwwgnuorglicenses ISO C Standard 716 Boolean type and values stdboolh ifndef __cplusplus define bool _Bool define true 1 define false 0 else 需要注意的是，_Bool 在 C 語言中被儲存為 int 型別。 下面這個函式在 C 和 C 中返回不同的值： extern int T int size void struct T int i int j return sizeof T C return sizeof int C return sizeof struct T 這是因為在 C 語言中，struct（結構體）型別前需要新增 struct，而在這個例子中，因為 T 前沒有 struct，所以它所代表的是在外部定義的 int 變數；而在 C 中，因為可以省略 struct，因此造成了歧義。然而，在 C 中如果使用這種形式，編譯器會更傾向於認為 T 是一個表示式，因此編譯會出錯；而在 C 語言中則不會。 參考資料 外部連結 Detailed comparison， C89 標準與 C 標準逐句比較 Incompatibilities Between ISO C and ISO C， David R Tribble 200108 Oracle Sun Microsystems C Migration Guide， section 311， Sun 編譯器有關連結的文件 Oracle Mixing C and C Code in the Same Program， 由 Steve Clamage（ANSI C 委員會主席）概述。 CategoryC 語言 CategoryC