1. 程式人生 > >『C/C++』ANSI C、C99、C11

『C/C++』ANSI C、C99、C11

C語言由Dennis M. Ritchie在1973年設計和實現。從那以後使用者逐漸增加。到1978年Ritchie和Bell實驗室的另一位程式專家Kernighan合寫了著名的《The C Programming Language》,將C語言推向全世界,許多國家都出了譯本,國內有一些C語言書就是這本書的翻譯或者編譯。由這本書定義的C語言後來被人們稱作 K&R C。 
隨著C語言使用得越來越廣泛,出現了許多新問題,人們日益強烈地要求對C語言進行標準化。這個標準化的工作在美國國家標準局(ANSI)的框架中進行(1983-1988),最終結果是1988年10月頒佈的ANSI標準X3.159-1989,也就是後來人們所說的ANSI C標準。由這個標準定義的C語言被稱作ANSI C。 
ANSI C標準很快被採納為國際標準和各國的標準。國際標準為ISO/IEC 9899-1990,中國國家標準GB/T 15272-94是國際ISO標準的中文翻譯。 
ANSI C標準化工作的一個主要目標是清除原來C語言中的不安全、不合理、不精確、不完善的東西。由此也產生了ANSI C與K&R C之間的差異。從總體上看,這些差異反應的是C語言走向完善、走向成熟。

____________________________________________________________________________________

ANSI C 對 K&R C 的修訂
(本段根據《C Programming Language》和C語言標準整理。不求完整,希望列出最常見的差異):
1. 對於原始檔內部的識別符號,有效的最小長度擴充到31個字元。檔案間連線時,識別符號的最小有效長度仍然為6個字元。(許多實現都支援更大的長度)
2. 增加了幾個新關鍵字:void,const,volatile,signed,enum。拋棄了老關鍵字entry。
3. 在換意字元 \ 之後寫非規定的序列,其作用確定為無定義。
4. 規定8和9都不是八進位制數的合法字元。
5. 引進了數的字尾字元:整數的U和L,浮點數的F和L。
6. 規定連續出現的字串常量將被拼接在一起。
7. 引進了“寬字元”的概念。
8. 將字元也確定為帶符號(signed)和不帶符號(unsigned)的。
9. 丟棄了long float(原來作為double的同義詞)。
10. 引入了void型別,用 (void*) 表示通用指標的型別(過去人們通常用 (char*))。
11. 對算術型別規定了最小表示範圍。要求每個C語言系統用標頭檔案(<limits.h>;和<float.h>;)說明實現中的具體規定。
12. 引進了列舉定義enum。
13. 採用了來自C++的型別修飾符,如const。
14. 規定字串常量是不可修改的。
15. 改變了算術型別的隱含轉換規則。
16. 刪去了一些過時賦值運算子,如 =+。規定賦值運算子都是基本單詞,如 += 之間不能有空格分隔。
17. 引進了與一元 - 運算子對應的一元 + 運算子。
18. 指向函式的指標可以直接放在函式呼叫的位置,不必顯式地寫間接操作。
19. 允許結構地整體賦值,作為函式引數和返回值傳遞。
20. 允許將取地址運算子作用於陣列,得到的是指向有關陣列的指標。
21. 標準規定 sizeof 運算子的返回值為 size_t 型別(某個無符號整型),這一型別在標準標頭檔案<stddef.h>;裡定義。同時在那裡定義的還有 ptrdiff_t 型別,它是指標減運算的結果型別。
22. 規定取地址運算子不能作用於 register 變數。
23. 規定移位表示式的型別為其左運算物件的型別。
24. 允許建立指向過陣列末元素一個位置的指標,以及對它的算術運算和關係運算。
25. (從C++)引進了包含引數型別的函式原型概念,引進了變長引數表函式的概念。仍允許老的形式,但僅僅是作為過時形式保留。
26. 標準規定任何區域性宣告的作用域僅僅是當前的塊(複合語句)。
27. 規定函式引數作為加入函式體(複合語句)的宣告,因此不能用變數宣告去覆蓋。
28. 有關名字空間的規定:所有結構、聯合和列舉標記在一個名字空間裡,標號是另一個名字空間。
29. 聯合變數在定義時也可以初始化,規定初始化其第一個成分。
30. 自動結構、聯合和陣列也可以初始化,但限制其初始化方式(其中只能包含常量表達式)。
31. 帶大小描述的字元陣列也可以用大小與之相同的字串常量初始化(結束的 \0 被刪除)。
32. 開關語句的控制表示式和case標號可以是任何整型的(包括字元型別)。

ANSI C通常叫C89
ISO/IEC 9899-1990 一般叫C90
後來還有C99和C11
最新標準應該是C11

GCC下面編譯程式的我一般都會在最後帶上引數 -std=c99

This second edition cancels and replaces the ?rst edition,ISO/IEC 9899:1990, as amended and corrected by ISO/IEC 9899/COR1:1994, ISO/IEC 9899/AMD1:1995, and
ISO/IEC 9899/COR2:1996. Major changes from the previous edition include:

— restricted character set support via digraphs and <iso646.h>(originally speci?ed in AMD1)
— wide character library support in <wchar.h> and <wctype.h>(originally speci?ed in AMD1)
— more precise aliasing rules via effective type
— restricted pointers
— variable-length arrays
—   ?exible array members 
—   staticand type quali?ers in parameter array declarators 
—   complex (and imaginary) support in <complex.h> 
—   type-generic math macros in <tgmath.h> 
—   the long long inttype and library functions 
—   increased minimum translation limits 
—   additional ?oating-point characteristics in <float.h> 
—   remove implicit int 
—   reliable integer division 
—   universal character names (\uand \U) 
—   extended identi?ers 
—   hexadecimal   ?oating-point   constants   and  %a and  %A printf/scanf conversion speci?ers 
—   compound literals 
—   designated initializers 
—   //comments 
—   extended   integer   types   and   library   functions   in  <inttypes.h> and <stdint.h> 
—   remove implicit function declaration 
—   preprocessor arithmetic done in intmax_t/uintmax_t 
—   mixed declarations and code 
—   new block scopes for selection and iteration statements 
—   integer constant type rules 
—   integer promotion rules 
—   vararg macros 
—   the vscanffamily of functions in <stdio.h>and <wchar.h> 
—   additional math library functions in <math.h> 
—   ?oating-point environment access in <fenv.h> 
—   IEC 60559 (also known as IEC 559 or IEEE arithmetic) support 
—   trailing comma allowed in enumdeclaration 
—   %lfconversion speci?er allowed in printf 
—    inline functions 
—    the snprintffamily of functions in <stdio.h> 
—    boolean type in <stdbool.h> 
—    idempotent type quali?ers 
—    empty macro arguments 
—    new struct type compatibility rules (tag compatibility) 
—    additional prede?ned macro names 
—  _Pragmapreprocessing operator 
—    standard pragmas 
—  __func__prede?ned identi?er 
—  VA_COPYmacro 
—    additional strftimeconversion speci?ers 
—    LIA compatibility annex 
—    deprecate ungetcat the beginning of a binary ?le 
—    remove deprecation of aliased array parameters

C99是標準ISO/IEC 9899:1999的簡稱。

c99是在c89的基礎上發展起來的,增加了基本資料型別,關鍵字和一些系統函式等。其實在初學階段C89(ANSI C)和C99的區別是不易察覺的,所以不必太在意這個。

C99有一部分是對於大字符集的優化(很多資料上寫的是ANSI標準化),還加入了一些資料庫函式,是C89之後的標準,我們用的C是C89標準的,C++是C89編寫的,目前的C99標準其實在以前的編譯器中就或多或少的支援了,目前完全支援的有這些:GCC、Borland C++等。
2011年12月8號,ISO 釋出了新的 C 語言的新標準——C11,之前被稱為C1X,官方名稱 ISO/IEC 9899:2011。


C11相比C99的變化:

1. 對齊處理操作符 alignof,函式 aligned_alloc(),以及 標頭檔案 <stdalign.h>。見 7.15 節。
2. _Noreturn 函式標記,類似於 gcc 的 __attribute__((noreturn))。例子:
_Noreturn void thrd_exit(int res);
3. _Generic 關鍵詞,有點兒類似於 gcc 的 typeof。例子:
#define cbrt(X) _Generic((X), long double: cbrtl, \
default: cbrt, \
float: cbrtf)(X)
4. 靜態斷言( static assertions),_Static_assert(),在解釋 #if 和 #error 之後被處理。例子:
_Static_assert(FOO > 0, "FOO has a wrong value");
5. 刪除了 gets() 函式,C99中已經將此函式被標記為過時,推薦新的替代函式 gets_s()。
6. 新的 fopen() 模式,(“…x”)。類似 POSIX 中的 O_CREAT|O_EXCL,在檔案鎖中比較常用。
7. 匿名結構體/聯合體,這個早已經在 gcc 中了,我們並不陌生,定義在 6.7.2.1 p13。
8. 多執行緒支援,包括:_Thread_local,標頭檔案 <threads.h>,裡面包含執行緒的建立和管理函式(比如 thrd_create(),thrd_exit()),mutex (比如 mtx_lock(),mtx_unlock())等等,更多內容清參考 7.26 節。
9. _Atomic型別修飾符和 標頭檔案 <stdatomic.h>,見 7.17 節。
10. 帶邊界檢查(Bounds-checking)的函式介面,定義了新的安全的函式,例如 fopen_s(),strcat_s() 等等。更多參考 Annex K。
11. 改進的 Unicode 支援,新的標頭檔案 <uchar.h> 等。
12. 新增 quick_exit() 函式,作為第三種終止程式的方式,當 exit() 失敗時可以做最少的清理工作(deinitializition),具體見 7.22.4.7。
13. 建立複數的巨集, CMPLX(),見 7.3.9.3。
14. 更多浮點數處理的巨集 (More macros for querying the characteristics of floating point types, concerning subnormal floating point numbers and the number of decimal digits the type is able to store)。
15. struct timespec 成為 time.h 的一部分,以及巨集 TIME_UTC,函式 timespec_get()。

一個是標準,一個實現。
GNU C實現了STD C的標準功能,且額外擴充套件諸多強大API.