-
c99
鎖定
C99 (以前稱為C9X )是ISO / IEC 9899:1999的非正式名稱,在1999年推出,被ANSI於2000年3月採用。它是C編程語言標準的過去版本。 它擴展了以前的版本( C90 ),增加了語言和標準庫的新功能,並幫助實現更好地利用可用的計算機硬件,如IEEE 754-1985浮點運算和編譯器技術,最主要的增強在數值處理上。 2011年發佈的C編程語言標準的C11版本取代了C99。
- 中文名
- C99
- 外文名
- ISO / IEC 9899:1999
- 別 名
- C9X
- 標準編號
- ISO/IEC 9899:1999
- 歷史版本
- C89
- 後續版本
- C11
目錄
- 1 信息介紹
- 2 歷史
- 3 新特性
- ▪ 增加restrict指針
- ▪ inline(內聯)關鍵字
- ▪ 新增數據類型
- ▪ 對數組的增強
- ▪ 單行註釋
- ▪ 分散代碼與聲明
- ▪ 預處理程序的修改
- ▪ for語句內的變量聲明
- ▪ 複合賦值
- ▪ 柔性數組結構成員
- ▪ 複合賦值初始化符
- ▪ printf和scanf函數系列的增強
- ▪ C99新增的庫
- ▪ _ func__ 預定義標識符
c99信息介紹
在ANSI的標準確立後,C語言的規範在一段時間內沒有大的變動,然而C++在自己的標準化創建過程中繼續發展壯大。《標準修正案一》在1994年為C語言創建了一個新標準,但是隻修正了一些 C89 標準中的細節和增加更多更廣的國際字符集支持。不過,這個標準引出了1999年ISO 9899:1999的發表。它通常被稱為C99。C99被ANSI於2000年3月採用。
[1]
C99是在C89/90的基礎上發展起來的,增加了基本數據類型、關鍵字和一些系統函數等。
C99有一部分是對於增加了寬字符集,還加入了一些庫函數,是繼C89標準之後的第二個C語言官方標準。第一個C++語言官方標準C++98標準,就是基於C89編寫的,因此C99標準新增的語法特性在C++的編譯器中就或多或少地支持了,而完全或幾乎完全支持C99標準的主流編譯器有:GCC
[2]
、Clang
[3]
、Intel C++ Compiler
[4]
等。另外,Visual Studio2013也部分支持了C99語法特徵
[5]
。
c99歷史
ANSI於1989年制定了C編程語言的官方標準,並於1990年成為國際標準,C語言規範在一段時間內保持相對靜態,而C ++繼續發展,主要是在其自身的標準化工作中。規範修正案1在1995年為C制定了一個新標準,但只是為了糾正1989年標準的一些細節,併為國際字符集增加了更廣泛的支持。該標準在20世紀90年代後期進行了進一步修訂,導致1999年出版了ISO / IEC 9899:1999,並於2000年5月作為ANSI標準採用。該標準版本定義的語言通常稱為“ C99" 。國際C標準由ISO / IEC JTC1 / SC22/ WG14工作組維護。
[6]
c99新特性
在ANSI標準化發佈了C89標準以後,C語言的標準在一段相當的時間內都保持不變,儘管C++繼續在改進。(實際上,Normative Amendment1在1995年已經開發了一個新的C語言版本(即C95)。但是這個版本很少為人所知。)標準在90年代才經歷了改進,這就是ISO/IEC 9899:1999(1999年出版)。這個版本就是通常提及的C99。
[7]
c99增加restrict指針
C99中增加了適用於指針的 restrict 類型修飾符,它是初始訪問指針所指對象的惟一途徑,因此只有藉助restrict 指針表達式才能訪問對象。restrict 指針主要用做函數形參,或者指向由malloc( ) 函數所分配的內存變量。restrict 數據類型不改變程序的語義。
[7]
c99inline(內聯)關鍵字
c99新增數據類型
_Bool:值是0或1,C99中增加了用來定義bool,true以及false 宏的頭文件< stdbool. h>,以便程序員能夠編寫同時兼容於C與C++的應用程序,在編寫新的應用程序時,應該使用< stdbool. h >頭文件的 bool 宏。
[7]
float_ Complex; float_ Imaginary; double_ .Complex ; double_ Imaginary; long double_ Complex; long double_ Imaginary.
<complex. h>頭文件中定義了 Complex 和 lmaginary 宏,並將它們擴展為 _Complex 和_Imaginary,因此在編寫新的應用程序時,應該使用< stdbool.h >頭文件中的 complex 和 imaginary 宏。
[7]
long long int:C99標準中引進了long long int ( - ( 2e63- 1)至 2e63 - 1) 和 unsigned longlong int (0至2e64 - 1),long long int 能夠支持的整數長度為64位。
[7]
c99對數組的增強
可變長數組(VLA):C99中,程序員聲明數組時,數組的維數可以由任意有效的整型表達式確定,包括只在運行時才能確定其值的表達式,這類數組就叫做可變長數組。但是隻有局部數組才可以是變長的。可變長數組的維數在數組生存期內是不變的,也就是説,可變長數組不是動態的。可以變化的只是數組的大小。可以使用*來定義不確定長的可變長數組。
[7]
c99單行註釋
c99分散代碼與聲明
# include < stdio. h> int main( void ) int numl = 3; printf("% d / n" ,num1); int num2 = 10; printf("% d / n" ,num2); return(0);
c99預處理程序的修改
# define identifier (... ) replacement_ list # define identifier ( identifier_ list, ... ) replacement_ list
如果宏定義中的identifier__list以省略號結尾,則意味着調用中的參數比宏定義中的參數(不包括省略號)多;否則,宏定義中參數的數目(包括由預處理標記組成的參數)與調用中參數的數目匹配。對於在其參數中使用省略號表示法的#define預處理指令,在其替換列表中使用標識符__ VA_ ARGS__。
[7]
(2)_ Pragma 操作符。
STDC FP_ CONTRACTON/OFF/DEFAULT
STDC FEVN ACCESSON/OFF/DEFAULT
STDC CX_ LIMITED_ RANGEON/OFF/ DEFAULT
c99for語句內的變量聲明
for (int i=0; i<10; i+ + ) { //1oop body };
c99複合賦值
C99中,複合賦值中,可以指定對象類型的數組、結構或聯合表達式,當使用複合賦值時,應在括弧內指定類型,後跟由花括號圍起來的初始化列表;若類型為數組,則不能指定數組的大小,建成的對象是未命名的。
[7]
c99柔性數組結構成員
C99中,結構中的最後一個元素允許是未知大小的數組,這就叫做柔性數組成員,但結構中的柔性數組成員前面必須至少一個其他成員。柔性數組成員允許結構中包含一個大小可變的數組,sizeof返回的這種結構大小不包括柔性數組的內存,包含柔性數組成員的結構用malloc( )函數進行內存的動態分配。並且分配的內存應該大於結構的大小,以適應柔性數組的預期大小。
[7]
c99複合賦值初始化符
用於數組的格式:
[index] = vol;
int x[10] = { [0] = 10,[5] = 30 };
例如:
struct example { int k, m, n; } object = {m=10,n=200};
c99printf和scanf函數系列的增強
C99 中 printf( ) 和 scanf( ) 函數系列引進了處理 long long int 和 unsigned long long int 數據類型的特性。long long int類型的格式修飾符是II,在printf()和scanf()函數中,II適用於d.i.o.u和x格式説明符。
[7]
[ - ]0xh, hhhhp + d
c99C99新增的庫
- <fenv.h> 給出對浮點狀態標記和浮點環境的其他方面的訪問
- <iso646.h> 用於定義對應各種運算符的宏
- <stdint.h> 定義標準的、可移植的整型類型集合
- <tgmath.h> 定義一般類型的浮點宏
- <wchar.h> 用於支持多字節和寬字節函數
c99_ func__ 預定義標識符
c99冪等限定符
c99static及數組聲明符的限定符
如果您指定void foo(int * restrict a);等類型限定符,則C編譯器使用實質上與聲明限定指針相同的數組語法void foo(int a [ restrict ]);表示它。
[7]
C編譯器還使用static限定符保留關於數組大小的信息。例如,如果指定voidfoo(int a[10]) ,則編譯器仍將它表達為void foo (int *a)。 按以下所示使用static限定符:void foo(int a [static 10]),讓編譯器知道指針a不是NULL,並且使用它可訪問至少包含十個元素的整數數組。
[7]
c99設計
特別是,缺少類型説明符的聲明不再隱含假定的int。C標準委員會認為,編譯器診斷無意中遺漏類型説明符比靜默處理依賴於隱式int遺留代碼更有價值。在實踐中,編譯器可能會顯示警告,然後假設為int並繼續翻譯程序。
[7]
- 混合聲明和代碼:變量聲明不再侷限於文件範圍或複合語句(塊)的開頭,便於靜態單一賦值形式
- 可變長度數組(雖然隨後在C11中降級為條件特徵,不需要支持實現)
- 靈活的陣列成員
- 新的庫函數,例如snprintf
- type-generic數學(宏)函數,在<tgmath.h>,它根據float,double或long double參數等選擇數學庫函數。
- 改進了對IEEE浮點的支持
- 指定的初始化者
- 複合文字(例如,可以在函數調用中構造結構:function((struct x) {1, 2}))
- 支持可變參數宏(具有可變數量參數的宏)
- 通用字符名稱,允許用户變量包含除標準字符集之外的其他字符
- 參數聲明中數組索引中的關鍵字static
c99關鍵字
c99數據類型關鍵字
1、char [tɑ:]:聲明字符型變量或函數
2、double [dbl] :聲明雙精度變量或函數
3、enum :聲明枚舉類型
4、float [flut] :聲明浮點型變量或函數
5、int[int]: 聲明整型變量或函數
6、long [l] :聲明長整型變量或函數
7、short [:t] :聲明短整型變量或函數
8、signed:聲明有符號類型變量或函數
9、struct:聲明結構體變量或函數
11、unsigned [n'saind]:聲明無符號類型變量或函數
12、void [vid] :聲明函數無返回值或無參數,聲明無類型指針
c99控制語句關鍵字
A循環語句
1、for [f, f:]:一種循環語句
3、while [wail] :循環語句的循環條件
4、break [breik]:跳出當前循環
5、continue[kntinju:]:結束當前循環,開始下一輪循環
B條件語句
1、if [if]: 條件語句
2、else [els] :條件語句否定分支(與 if 連用)
3、goto:無條件跳轉語句
C開關語句
1、switch [swit]:用於開關語句
2、case [keis]:開關語句分支
3、default [dif:lt]:開關語句中的“其他”分支
D返回語句
1、return [rit:n]:子程序返回語句
c99存儲類型關鍵字
1、auto [:tu] :聲明自動變量
2、extern:聲明變量是在其他文件中聲明
3、register [redist]:聲明寄存器變量
4、static[sttik] :聲明靜態變量
c99其它關鍵字
1、const :聲明只讀變量
2、sizeof:計算數據類型長度
3、typedef:用以給數據類型取別名
4、volatile [vltail]:説明變量在程序執行中可被隱含地改變
c99C99新增
1、inline關鍵字用來定義一個類的內聯函數,引入它的主要原因是用它替代C中表達式形式的宏定義
引入原因:C語言是一個效率很高的語言,這種宏定義在形式及使用上像一個函數,但它使用預處理器實現,沒有了參數壓棧,代碼生成等一系列的操作
2、restrict關鍵字只用於限定指針;該關鍵字用於告知編譯器,所有修改該指針所指向內容的操作全部都是基於(base on)該指針的,即不存在其它進行修改操作的途徑;這樣的後果是幫助編譯器進行更好的代碼優化,生成更有效率的彙編代碼。
3、_Bool關鍵字是用於表示布爾值。包含標準頭文件 stdbool.h 後,我們可以用 bool 代替 _Bool ,true 代替 1 ,false 代替 0 。
C99標準中定義的複數類型如下:float_Complex; float_Imaginary; double_Complex; double_Imaginary; long double_Complex; long double_Imaginary.
c99版本檢測
標準宏__STDC_VERSION__定義為值199901L,表示C99支持可用。與C90的__STDC__宏一樣,__STDC_VERSION__可用於編寫將針對C90和C99編譯器進行不同編譯的代碼,如此示例中確保在任何一種情況下都可以使用inline(通過在C90中將其替換為static以避免鏈接器錯誤) )。
[7]
#if __STDC_VERSION__> = 199901L / *“inline”是一個關鍵字* /
c99實施
從歷史上看,Microsoft在其Visual C ++工具中實現新C功能的速度很慢,而主要側重於支持C ++標準的開發。然而,隨着Visual C ++ 2013的引入,Microsoft實現了C99的有限子集,它在Visual C ++ 2015中進行了擴展。
[7]
編譯器 | 支持程度 | C99兼容性細節 |
---|---|---|
橡子C / C ++ | 局部 | 官方文檔指出支持“大多數”編譯器功能,以及庫函數的“一些”。 |
AMD x86Open64編譯器套件 | 大多 | C99的支持是否與GCC相同。 |
cc65 | 局部 | 未實現完整的C89和C99支持,部分原因是平台限制(MOS技術6502)。某些C99類型沒有計劃支持,如_Complex和64位整數(long long)。 |
局部 | 支持主要的C99功能。 | |
大多 | 支持除C99浮點pragma之外的所有功能。 | |
CompCert | 大多 | 經過認證的編譯器,正式證明是正確的。支持除C99複數和VLA之外的所有功能,以及對switch語句的小限制(沒有Duff的設備)。 |
cparser | 充分 | 支持C99功能。 |
C ++ Builder | 僅在64位模式下,因為後者是CLang fork | |
數字火星C / C ++編譯器 | 局部 | 缺少對某些功能的支持,例如<tgmath.h>和_Pragma。 |
大多 | 截至2014年6月,主線GCC中缺少擴展標識符,標準編譯指示和IEEE 754 / IEC 60559浮點支持。此外,某些功能(例如擴展整數類型和新庫函數)必須由C標準庫提供,並且不在GCC範圍內。GCC的4.6和4.7版本也提供相同級別的合規性。部分IEEE 754支持,即使硬件是兼容的:可能需要一些編譯器選項來避免不正確的優化(例如,-std = c99和-fsignaling-nans),但完全支持定向舍入模式是即使使用-frounding-math也會丟失。 | |
充分 | ||
IBM C for AIX,V6和XL C / C ++V11.1 for AIX | 充分 | |
IBM Rationallogiscope | 充分 | 在Logiscope 6.3之前,只支持C99的基本結構。Logiscope 6.4及更高版本正式支持C99。 |
波特蘭集團PGI C / C ++ | 充分 | |
IAR系統 嵌入式工作台 | 大多 | 不支持UCN(通用字符名稱)。用於嵌入式目標的編譯器,例如ARM,Coldfire,MSP430,AVR,AVR32,8051,...... No x86目標。 |
英特爾C ++編譯器 | 大多 | |
Microsoft Visual C ++ | 部分 | Visual C ++ 2012及更早版本不支持C99。 Visual C ++ 2013實現了編譯流行的開源項目所需的有限C99子集。 Visual C ++ 2015實現了C99標準庫,但依賴於編譯器尚未支持的編譯器功能的任何庫功能除外(例如,<tgmath.h>未實現)。 |
打開Watcom | 局部 | 實現標準中最常用的部分。但是,它們僅通過未記錄的命令行開關“-za99”啓用。自從v1.0之前的C90擴展以來,已經捆綁了三個C99功能:C ++樣式註釋(//),靈活的數組成員,枚舉聲明中允許的尾隨逗號。 |
Pelles C. | 充分 | 支持所有C99功能。 |
便攜式C編譯器 | 局部 | 致力於符合C99標準。 |
太陽工作室 | 滿 | |
阿姆斯特丹編譯器套件 | 不 | C99前端目前正在調查中。 |
微小的C編譯器 | 局部 | 不支持複數。支持可變長度數組,但不支持函數。開發人員表示“TCC正朝着完全符合ISOC99的方向發展”。 |
VBCC | 局部 |
c99未來的工作
自批准1999 C標準以來,標準工作組編寫了技術報告,規定了對嵌入式處理,附加字符數據類型(Unicode支持)和具有改進邊界檢查的庫函數的改進支持。繼續處理有關十進制浮點,附加數學特殊函數和其他動態內存分配函數的技術報告。C和C ++標準委員會一直在協調線程編程的規範。
[8]
c99後續標準
C11標準是C語言標準的第三版,前一個標準版本是C99標準。2011年12月8日,國際標準化組織(ISO)和國際電工委員會(IEC) 旗下的C語言標準委員會(ISO/IEC JTC1/SC22/WG14)正式發佈了C11標準。
[8]
C11標準的最終定稿的草案是免費開放的,為N1570,但是正式標準文件需要198瑞士法郎。
[8]
c99相比C99的區別
1. 對齊處理操作符 alignof,函數 aligned_alloc(),以及 頭文件 <stdalign.h>。
[9]
2. _Noreturn 函數標記,類似於gcc的 __attribute__((noreturn))。例子:
[9]
_Noreturn void thrd_exit(int res);
#include<stdio.h> #defineGENERAL_ABS(x)_Generic((x),int:abs,float:fabsf,double:fabs)(x) int main(void) { printf("intabs:%d\n",GENERAL_ABS(-12)); printf("floatabs:%f\n",GENERAL_ABS(-12.04f)); printf("doubleabs:%f\n",GENERAL_ABS(-13.09876)); int a=10; int b=0,c=0; _Generic(a+0.1f,int:b,float:c,default:b)++; printf("b=%d,c=%d\n",b,c); _Generic(a+=1.1f,int:b,float:c,default:b)++; printf("a=%d,b=%d,c=%d\n",a,b,c); }
4. 靜態斷言( static assertions),_Static_assert(),在解釋 #if 和 #error 之後被處理。例子:
[9]
_Static_assert(FOO > 0, "FOO has a wrong value");
5. 刪除了 gets() 函數,C99中已經將此函數被標記為過時,推薦新的替代函數 gets_s()。
[9]
6. 新的 fopen() 模式,(“…x”)。類似 POSIX 中的 O_CREAT|O_EXCL,在文件鎖中比較常用。
[9]
8. 多線程支持,包括:_Thread_local,頭文件 <threads.h>,裏面包含線程的創建和管理函數(比如 thrd_create(),thrd_exit()),mutex (比如 mtx_lock(),mtx_unlock())等等。
[9]
10. 帶邊界檢查(Bounds-checking)的函數接口,定義了新的安全的函數,例如 fopen_s(),strcat_s() 等等。
[9]
#include<stdio.h> #include<uchar.h> size_t UTF16StrLen(constchar16_t*utf16String) { if(utf16String==NULL) return0; size_t index; for(index=0;utf16String[index]!=u'\0';index++); returnindex; } size_t UTF16ToUTF8(char*mbBuffer,constchar16_t*utf16String) { if(mbBuffer==NULL||utf16String==NULL) return0; mbstate_t state={}; size_t mbIndex=0; for(int utf16Index=0;utf16String[utf16Index]!=u'\0';utf16Index++) { constsize_tlength=c16rtomb(&mbBuffer[mbIndex],utf16String[utf16Index],&state); mbIndex+=length; } mbBuffer[mbIndex]='\0'; return mbIndex; } int main(intargc,char*argv[]) { char16_t ch=u'好'; char chBuffer[64]; mbstate_t state={}; size_t length=c16rtomb(chBuffer,ch,&state); chBuffer[length]='\0'; printf("TheUTF-8characterlengthis:%zu,andthecharacteris:%s\n",length,chBuffer); const char * utf8Str=u8"你好,世界。"; printf("TheUTF-8stringis:%s\n",utf8Str); const char16_t *utf16Str=u"你好,世界。"; printf("Theutf16stringlengthis:%zu\n",UTF16StrLen(utf16Str)); length=UTF16ToUTF8(chBuffer,utf16Str); printf("TheUTF-8stringlengthis:%zu,andthecontentis:%s\n",length,chBuffer); printf("IftheconvertedUTF-8stringisequaltotheoriginalone?%s\n",strcmp(chBuffer,utf8Str)==0?"YES":"NO"); }
12. 新增 quick_exit() 函數,作為第三種終止程序的方式,當 exit()失敗時可以做最少的清理工作(deinitializition)。
[9]
13. 創建複數的宏, CMPLX()。
[9]
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)。
[9]
15. struct timespec 成為 time.h 的一部分,以及宏 TIME_UTC,函數 timespec_get()。
[9]
- 參考資料
-
- 1. 鞠曉傑, 吳華森, 張有光. 國際RFID技術標準研究系列報道(九)ISO/IEC RFID基礎技術標準體系研究[J]. 信息技術與標準化, 2010(7):45-48.
- 2. Status of C99 features in GCC .GCC, the GNU Compiler Collection[引用日期2014-11-23]
- 3. Clang Compiler User’s Manual ."clang" C Language Family Frontend for LLVM[引用日期2014-11-23]
- 4. C99 Support in Intel® C++ Compiler .Intel® Developer Zone.2014-08-26[引用日期2014-11-23]
- 5. C99 library support in Visual Studio 2013 .MSDN Blogs.2013-07-19[引用日期2014-11-23]
- 6. C99最終版草案N1256 .ISO開放標準[引用日期2014-11-16]
- 7. 陸麗娜主編;丁凰,繆相林,趙彩副主編.C語言程序設計:西安交通大學出版社,2012.02:第277頁
- 8. ISO/IEC JTC1/SC22/WG14 - C: Approved standards .Open Standards[引用日期2019-11-05]
- 9. ISO/IEC 9899:201x - N1570 - Programming languages - C .Open Standards[引用日期2019-11-05]
- 10. 張仕,黃晞,嚴曉明,數據結構實驗教程 C/C++語言版 第2版,廈門大學出版社,2018.06,第4頁