C89和C99標準比較
阿新 • • 發佈:2019-01-23
1、增加restrict指標
C99中增加了公適用於指標的restrict型別修飾符,它是初始訪問指標所指物件的惟一途徑,因此只有藉助restrict指標表示式才能訪問物件。restrict指標指標主要用做函式變元
,或者指向由malloc()函式所分配的記憶體變數。restrict資料型別不改變程式的語義。
如果某個函式定義了兩個restrict指標變元,編譯程式就假定它們指向兩個不同的物件,memcpy()函式就是restrict指標的一個典型應用示例。C89中memcpy()函式原型如下:
void *memcpy (void *s1, const void *s2, size_t size);
如果s1和s2所指向的物件重疊,其操作就是未定義的。memcpy()函式只能用於不重疊的物件。
C99中memcpy()函式原型如下:
void *memcpy(void *restrict s1, const void *restrict s2,size_t size);
通過使用restrict修飾s1和s2變元,可確保它們在該原型中指向不同的物件。
2、inline(內聯)關鍵字
行內函數除了保持結構化和函式式的定義方式外,還能使程式設計師寫出高效率的程式碼.函式的每次呼叫與返回都會消耗相當大的系統資源,尤其是當函式呼叫發生在重複次數很多的迴圈
語句中時.一般情況下,當發生一次函式呼叫時,變元需要進棧,各種暫存器記憶體需要儲存.當函式返回時,暫存器的內容需要恢復。如果該函式在程式碼內進行聯機擴充套件,當代碼執行時
,這些儲存和恢復操作旅遊活動會再發生,而且函式呼叫的執行速度也會大大加快。
函式的聯機擴充套件會產生較長的程式碼,所以只應該內聯對應用程式效能有顯著影響的函式以及長度較短的函式。
3、新增資料型別
_Bool
值是0或1。C99中增加了用來定義bool、true以及false巨集的標頭檔案夾<stdbool.h>,以便程式設計師能夠編寫同時兼容於C與C++的應用程式。在編寫新的應用程式時,應該使用
<stdbool.h>標頭檔案中的bool巨集。
_Complex and _Imaginary
C99標準中定義的複數型別如下:float_Complex; float_Imaginary; double_Complex; double_Imaginary; long double_Complex; long double_Imaginary.
<complex.h>標頭檔案中定義了complex和imaginary巨集,並將它們擴充套件為_Complex和_Imaginary,因此在編寫新的應用程式時,應該使用<stdbool.h>標頭檔案中的complex和imaginary巨集。
long long int
C99標準中引進了long long int(-(2e63 - 1)至2e63 - 1)和unsigned long long int(0 - 2e64 - 1)。long long int能夠支援的整數長度為64位。
4、對陣列的增強
可變長陣列
C99中,程式設計師宣告陣列時,陣列的維數可以由任一有效的整型表示式確定,包括只在執行時才能確定其值的表示式,這類陣列就叫做可變長陣列,但是隻有區域性陣列才可以是變長的.
可變長陣列的維數在陣列生存期內是不變的,也就是說,可變長陣列不是動態的.可以變化的只是陣列的大小.可以使用*來定義不確定長的可變長陣列.
陣列宣告中的型別修飾符
在C99中,如果需要使用陣列作為函式變元,可以在陣列宣告的方括號內使用static關鍵字,這相當於告訴編譯程式,變元所指向的陣列將至少包含指定的元素個數。也可以在數
組宣告的方括號內使用restrict,volatile,const關鍵字,但只用於函式變元。如果使用restrict,指標是初始訪問該物件的惟一途徑。如果使用const,指標始終指向同一個陣列
。使用volatile沒有任何意義。
5、單行註釋
6、分散程式碼與宣告
7、預處理程式的修改
1、變元列表
巨集可以帶變元,在巨集定義中用省略號(...)表示。內部預處理識別符號__VA_ARGS__決定變元將在何處得到替換。例:#define MySum(...) sum(__VA_ARGS__) 語句MySum(k,m,n);
將被轉換成:sum(k, m, n);
變元還可以包含變元。例: #define compare(compf, ...) compf(__VA_ARGS__) 其中的compare(strcmp,"small", "large"); 將替換成:strcmp("small","large");
2、_Pragma運算子
C99引入了在程式中定義編譯指令的另外一種方法:_Pragma運算子。格式如下:_Pragma("directive") 其中directive是要滿打滿算的編譯指令。_Pragma運算子允許編譯指令參
與巨集替換。
3、內部編譯指令
STDC FP_CONTRACT ON/OFF/DEFAULT 若為ON,浮點表示式被當做基於硬體方式處理的獨立單元。預設值是定義的工具。
STDC FEVN_ACCESS ON/OFF/DEFAULT 告訴編譯程式可以訪問浮點環境。預設值是定義的工具。
STDC CX_LIMITED_RANGE ON/OFF/DEFAULT 若值為ON,相當於告訴編譯程式某程式某些含有複數的公式是可靠的。預設是OFF。
4、新增的內部巨集
__STDC_HOSTED__ 若作業系統存在,則為1
__STDC_VERSION__ 199991L或更高。代表C的版本
__STDC_IEC_599__ 若支援IEC 60559浮點運算,則為1
__STDC_IEC_599_COMPLEX__ 若支援IEC 60599複數運算,則為1
__STDC_ISO_10646__ 由編譯程式支援,用於說明ISO/IEC 10646標準的年和月格式:yyymmmL
8、for語句內的變數宣告
C99中,程式設計師可以在for語句的初始化部分定義一個或多個變數,這些變數的作用域僅於本for語句所控制的迴圈體內。
9、複合賦值
C99中,複合賦值中,可以指定物件型別的陣列、結構或聯合表示式。當使用複合賦值時,應在括弧內指定型別,後跟由花括號圍起來的初始化列表;若型別為陣列,則不能指定數
組的大小。建成的物件是未命名的。例: double *fp = (double[]) {1.1, 2.2, 3.3};
該語句用於建立一個指向double的指標fp,且該指標指向這個3元素陣列的第一個元素。 在檔案域內建立的複合賦值只在程式的整個生存期內有效。在模組內建立的複合賦值是
區域性物件,在退出模組後不再存在。
10、柔性陣列結構成員
C99中,結構中的最後一個元素允許是未知大小的陣列,這就叫做柔性陣列成員,但結構中的柔性陣列成員前面必須至少一個其他成員。柔性陣列成員允許結構中包含一個大小可變
的陣列。sizeof返回的這種結構大小不包括柔性陣列的記憶體。包含柔性陣列成員的結構用malloc()函式進行記憶體的動態分配,並且分配的記憶體應該大於結構的大小,以適應柔性數
組的預期大小。
11、指定的初始化符
C99中,該特性對經常使用稀疏陣列的程式設計師十分有用。指定的初始化符通常有兩種用法:用於陣列,以及用於結構和聯合。 用於陣列的格式:[index] = vol; 其中,index表
示陣列的下標,vol表示本陣列元素的初始化值。例如: int x[10] = {[0] = 10, [5] = 30}; 其中只有x[0]和x[5]得到了初始化。 用於結構或聯合的格式如下:
member-name(成員名稱) 對結構進行指定的初始化時,允許採用簡單的方法對結構中的指定成員進行初始化。例如: struct example{ int k, m, n; } object = {m = 10,
n = 200}; 其中,沒有初始化k。對結構成員進行初始化的順序沒有限制。
12、printf()和scanf()函式系列的增強
C99中printf()和scanf()函式系列引進了處理long long int和unsigned long long int資料型別的特性。long long int 型別的格式修飾符是ll。在printf()和scanf()函式中
,ll適用於d, i, o, u 和x格式說明符。
另外,C99還引進了hh修飾符。當使用d, i, o, u和x格式說明符時,hh用於指定char型變元。ll和hh修飾符均可以用於n說明符。
格式修飾符a和A用在printf()函式中時,結果將會輸出十六進位制的浮點數。格式如下:[-]0xh, hhhhp + d 使用A格式修飾符時,x和p必須是大小。A和a格式修飾符也可以用
在scanf()函式中,用於讀取浮點數。呼叫printf()函式時,允許在%f說明符前加上l修飾符,即%lf,但不起作用。
13、C99新增的庫
C89中標準的標頭檔案
<assert.h> 定義巨集assert()
<ctype.h> 字元處理
<errno.h> 錯誤報告
<float.h> 定義與實現相關的浮點值勤
<limits.h> 定義與實現相關的各種極限值
<locale.h> 支援函式setlocale()
<math.h> 數學函式庫使用的各種定義
<setjmp.h> 支援非區域性跳轉
<signal.h> 定義訊號值
<stdarg.h> 支援可變長度的變元列表
<stddef.h> 定義常用常數
<stdio.h> 支援檔案輸入和輸出
<stdlib.h> 其他各種宣告
<string.h> 支援串函式
<time.h> 支援系統時間函式
C99新增的標頭檔案和庫
<complex.h> 支援複雜演算法
<fenv.h> 給出對浮點狀態標記和浮點環境的其他方面的訪問
<inttypes.h> 定義標準的、可移植的整型型別集合。也支援處理最大寬度整數的函式
<iso646.h> 首先在此1995年第一次修訂時引進,用於定義對應各種運算子的巨集
<stdbool.h> 支援布林資料型別型別。定義巨集bool,以便兼容於C++
<stdint.h> 定義標準的、可移植的整型型別集合。該檔案包含在<inttypes.h>中
<tgmath.h> 定義一般型別的浮點巨集
<wchar.h> 首先在1995年第一次修訂時引進,用於支援多位元組和寬位元組函式
<wctype.h> 首先在1995年第一次修訂時引進,用於支援多位元組和寬位元組分類函式
14、__func__預定義識別符號
用於指出__func__所存放的函式名,類似於字串賦值。
其它特性的改動
放寬的轉換限制
限制 C89標準 C99標準
資料塊的巢狀層數 15 127
條件語句的巢狀層數 8 63
內部識別符號中的有效字元個數 31 63
外部識別符號中的有效字元個數 6 31
結構或聯合中的成員個數 127 1023
函式呼叫中的引數個數 31 127
不再支援隱含式的int規則
刪除了隱含式函式宣告
對返回值的約束
C99中,非空型別函式必須使用帶返回值的return語句.
擴充套件的整數型別
擴充套件型別 含義
int16_t 整數長度為精確16位
int_least16_t 整數長度為至少16位
int_fast32_t 最穩固的整數型別,其長度為至少32位
intmax_t 最大整數型別
uintmax_t 最大無符號整數型別
對整數型別提升規則的改進
C89中,表示式中型別為char,short int或int的值可以提升為int或unsigned int型別.
C99中增加了公適用於指標的restrict型別修飾符,它是初始訪問指標所指物件的惟一途徑,因此只有藉助restrict指標表示式才能訪問物件。restrict指標指標主要用做函式變元
,或者指向由malloc()函式所分配的記憶體變數。restrict資料型別不改變程式的語義。
如果某個函式定義了兩個restrict指標變元,編譯程式就假定它們指向兩個不同的物件,memcpy()函式就是restrict指標的一個典型應用示例。C89中memcpy()函式原型如下:
void *memcpy (void *s1, const void *s2, size_t size);
如果s1和s2所指向的物件重疊,其操作就是未定義的。memcpy()函式只能用於不重疊的物件。
C99中memcpy()函式原型如下:
void *memcpy(void *restrict s1, const void *restrict s2,size_t size);
通過使用restrict修飾s1和s2變元,可確保它們在該原型中指向不同的物件。
2、inline(內聯)關鍵字
行內函數除了保持結構化和函式式的定義方式外,還能使程式設計師寫出高效率的程式碼.函式的每次呼叫與返回都會消耗相當大的系統資源,尤其是當函式呼叫發生在重複次數很多的迴圈
語句中時.一般情況下,當發生一次函式呼叫時,變元需要進棧,各種暫存器記憶體需要儲存.當函式返回時,暫存器的內容需要恢復。如果該函式在程式碼內進行聯機擴充套件,當代碼執行時
,這些儲存和恢復操作旅遊活動會再發生,而且函式呼叫的執行速度也會大大加快。
函式的聯機擴充套件會產生較長的程式碼,所以只應該內聯對應用程式效能有顯著影響的函式以及長度較短的函式。
3、新增資料型別
_Bool
值是0或1。C99中增加了用來定義bool、true以及false巨集的標頭檔案夾<stdbool.h>,以便程式設計師能夠編寫同時兼容於C與C++的應用程式。在編寫新的應用程式時,應該使用
<stdbool.h>標頭檔案中的bool巨集。
_Complex and _Imaginary
C99標準中定義的複數型別如下:float_Complex; float_Imaginary; double_Complex; double_Imaginary; long double_Complex; long double_Imaginary.
<complex.h>標頭檔案中定義了complex和imaginary巨集,並將它們擴充套件為_Complex和_Imaginary,因此在編寫新的應用程式時,應該使用<stdbool.h>標頭檔案中的complex和imaginary巨集。
long long int
C99標準中引進了long long int(-(2e63 - 1)至2e63 - 1)和unsigned long long int(0 - 2e64 - 1)。long long int能夠支援的整數長度為64位。
4、對陣列的增強
可變長陣列
C99中,程式設計師宣告陣列時,陣列的維數可以由任一有效的整型表示式確定,包括只在執行時才能確定其值的表示式,這類陣列就叫做可變長陣列,但是隻有區域性陣列才可以是變長的.
可變長陣列的維數在陣列生存期內是不變的,也就是說,可變長陣列不是動態的.可以變化的只是陣列的大小.可以使用*來定義不確定長的可變長陣列.
陣列宣告中的型別修飾符
在C99中,如果需要使用陣列作為函式變元,可以在陣列宣告的方括號內使用static關鍵字,這相當於告訴編譯程式,變元所指向的陣列將至少包含指定的元素個數。也可以在數
組宣告的方括號內使用restrict,volatile,const關鍵字,但只用於函式變元。如果使用restrict,指標是初始訪問該物件的惟一途徑。如果使用const,指標始終指向同一個陣列
。使用volatile沒有任何意義。
5、單行註釋
6、分散程式碼與宣告
7、預處理程式的修改
1、變元列表
巨集可以帶變元,在巨集定義中用省略號(...)表示。內部預處理識別符號__VA_ARGS__決定變元將在何處得到替換。例:#define MySum(...) sum(__VA_ARGS__) 語句MySum(k,m,n);
將被轉換成:sum(k, m, n);
變元還可以包含變元。例: #define compare(compf, ...) compf(__VA_ARGS__) 其中的compare(strcmp,"small", "large"); 將替換成:strcmp("small","large");
2、_Pragma運算子
C99引入了在程式中定義編譯指令的另外一種方法:_Pragma運算子。格式如下:_Pragma("directive") 其中directive是要滿打滿算的編譯指令。_Pragma運算子允許編譯指令參
與巨集替換。
3、內部編譯指令
STDC FP_CONTRACT ON/OFF/DEFAULT 若為ON,浮點表示式被當做基於硬體方式處理的獨立單元。預設值是定義的工具。
STDC FEVN_ACCESS ON/OFF/DEFAULT 告訴編譯程式可以訪問浮點環境。預設值是定義的工具。
STDC CX_LIMITED_RANGE ON/OFF/DEFAULT 若值為ON,相當於告訴編譯程式某程式某些含有複數的公式是可靠的。預設是OFF。
4、新增的內部巨集
__STDC_HOSTED__ 若作業系統存在,則為1
__STDC_VERSION__ 199991L或更高。代表C的版本
__STDC_IEC_599__ 若支援IEC 60559浮點運算,則為1
__STDC_IEC_599_COMPLEX__ 若支援IEC 60599複數運算,則為1
__STDC_ISO_10646__ 由編譯程式支援,用於說明ISO/IEC 10646標準的年和月格式:yyymmmL
8、for語句內的變數宣告
C99中,程式設計師可以在for語句的初始化部分定義一個或多個變數,這些變數的作用域僅於本for語句所控制的迴圈體內。
9、複合賦值
C99中,複合賦值中,可以指定物件型別的陣列、結構或聯合表示式。當使用複合賦值時,應在括弧內指定型別,後跟由花括號圍起來的初始化列表;若型別為陣列,則不能指定數
組的大小。建成的物件是未命名的。例: double *fp = (double[]) {1.1, 2.2, 3.3};
該語句用於建立一個指向double的指標fp,且該指標指向這個3元素陣列的第一個元素。 在檔案域內建立的複合賦值只在程式的整個生存期內有效。在模組內建立的複合賦值是
區域性物件,在退出模組後不再存在。
10、柔性陣列結構成員
C99中,結構中的最後一個元素允許是未知大小的陣列,這就叫做柔性陣列成員,但結構中的柔性陣列成員前面必須至少一個其他成員。柔性陣列成員允許結構中包含一個大小可變
的陣列。sizeof返回的這種結構大小不包括柔性陣列的記憶體。包含柔性陣列成員的結構用malloc()函式進行記憶體的動態分配,並且分配的記憶體應該大於結構的大小,以適應柔性數
組的預期大小。
11、指定的初始化符
C99中,該特性對經常使用稀疏陣列的程式設計師十分有用。指定的初始化符通常有兩種用法:用於陣列,以及用於結構和聯合。 用於陣列的格式:[index] = vol; 其中,index表
示陣列的下標,vol表示本陣列元素的初始化值。例如: int x[10] = {[0] = 10, [5] = 30}; 其中只有x[0]和x[5]得到了初始化。 用於結構或聯合的格式如下:
member-name(成員名稱) 對結構進行指定的初始化時,允許採用簡單的方法對結構中的指定成員進行初始化。例如: struct example{ int k, m, n; } object = {m = 10,
n = 200}; 其中,沒有初始化k。對結構成員進行初始化的順序沒有限制。
12、printf()和scanf()函式系列的增強
C99中printf()和scanf()函式系列引進了處理long long int和unsigned long long int資料型別的特性。long long int 型別的格式修飾符是ll。在printf()和scanf()函式中
,ll適用於d, i, o, u 和x格式說明符。
另外,C99還引進了hh修飾符。當使用d, i, o, u和x格式說明符時,hh用於指定char型變元。ll和hh修飾符均可以用於n說明符。
格式修飾符a和A用在printf()函式中時,結果將會輸出十六進位制的浮點數。格式如下:[-]0xh, hhhhp + d 使用A格式修飾符時,x和p必須是大小。A和a格式修飾符也可以用
在scanf()函式中,用於讀取浮點數。呼叫printf()函式時,允許在%f說明符前加上l修飾符,即%lf,但不起作用。
13、C99新增的庫
C89中標準的標頭檔案
<assert.h> 定義巨集assert()
<ctype.h> 字元處理
<errno.h> 錯誤報告
<float.h> 定義與實現相關的浮點值勤
<limits.h> 定義與實現相關的各種極限值
<locale.h> 支援函式setlocale()
<math.h> 數學函式庫使用的各種定義
<setjmp.h> 支援非區域性跳轉
<signal.h> 定義訊號值
<stdarg.h> 支援可變長度的變元列表
<stddef.h> 定義常用常數
<stdio.h> 支援檔案輸入和輸出
<stdlib.h> 其他各種宣告
<string.h> 支援串函式
<time.h> 支援系統時間函式
C99新增的標頭檔案和庫
<complex.h> 支援複雜演算法
<fenv.h> 給出對浮點狀態標記和浮點環境的其他方面的訪問
<inttypes.h> 定義標準的、可移植的整型型別集合。也支援處理最大寬度整數的函式
<iso646.h> 首先在此1995年第一次修訂時引進,用於定義對應各種運算子的巨集
<stdbool.h> 支援布林資料型別型別。定義巨集bool,以便兼容於C++
<stdint.h> 定義標準的、可移植的整型型別集合。該檔案包含在<inttypes.h>中
<tgmath.h> 定義一般型別的浮點巨集
<wchar.h> 首先在1995年第一次修訂時引進,用於支援多位元組和寬位元組函式
<wctype.h> 首先在1995年第一次修訂時引進,用於支援多位元組和寬位元組分類函式
14、__func__預定義識別符號
用於指出__func__所存放的函式名,類似於字串賦值。
其它特性的改動
放寬的轉換限制
限制 C89標準 C99標準
資料塊的巢狀層數 15 127
條件語句的巢狀層數 8 63
內部識別符號中的有效字元個數 31 63
外部識別符號中的有效字元個數 6 31
結構或聯合中的成員個數 127 1023
函式呼叫中的引數個數 31 127
不再支援隱含式的int規則
刪除了隱含式函式宣告
對返回值的約束
C99中,非空型別函式必須使用帶返回值的return語句.
擴充套件的整數型別
擴充套件型別 含義
int16_t 整數長度為精確16位
int_least16_t 整數長度為至少16位
int_fast32_t 最穩固的整數型別,其長度為至少32位
intmax_t 最大整數型別
uintmax_t 最大無符號整數型別
對整數型別提升規則的改進
C89中,表示式中型別為char,short int或int的值可以提升為int或unsigned int型別.