C89標准和C99標准C11標准的區別


轉載 C89標准和C99標准C11標准的區別

C99對C89的改變

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、單行注釋
  引入了單行注釋標記 "//" , 可以象C++一樣使用這種注釋了。
6、分散代碼與聲明
7、預處理程序的修改
  a、變元列表
  宏可以帶變元,在宏定義中用省略號(...)表示。內部預處理標識符__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");
  b、_Pragma運算符
  C99引入了在程序中定義編譯指令的另外一種方法:_Pragma運算符。格式如下:
  _Pragma("directive")
  其中directive是要滿打滿算的編譯指令。_Pragma運算符允許編譯指令參與宏替換。
  c、內部編譯指令
  STDCFP_CONTRACT ON/OFF/DEFAULT 若為ON,浮點表達式被當做基於硬件方式處理的獨立
單元。默認值是定義的工具。
  STDCFEVN_ACCESS ON/OFF/DEFAULT 告訴編譯程序可以訪問浮點環境。默認值是定義的工具。
  STDC CX_LIMITED_RANGE ON/OFF/DEFAULT 若值為ON,相當於告訴編譯程序某程序某些含
有復數的公式是可靠的。默認是OFF。
  d、新增的內部宏
  __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語
句所控制的循環體內。比如:
代碼:
for(int i=0; i<10; i++){
    // do someting ...
}
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__所存放的函數名,類似於字符串賦值。
15、其它特性的改動
  放寬的轉換限制
    限制             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中,每種整數類型都有一個級別.例如:long long int 的級別高於int, int的級別高於char
等.在表達式中,其級別低於int或unsigned int的任何整數類型均可被替換成int或unsigned int類型.

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。示例代碼:

#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));
 
inta=10;
intb=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 之后被處理。例子:
_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> 等。實例代碼:

 1 #include<stdio.h>
 2 
 3 #include<uchar.h>
 4  
 5 size_tUTF16StrLen(constchar16_t*utf16String)
 6 {
 7 
 8 if(utf16String==NULL)
 9 
10 return0;
11 size_tindex;
12 
13 
14 for(index=0;utf16String[index]!=u'\0';index++);
15 returnindex;
16 }
17 size_tUTF16ToUTF8(char*mbBuffer,constchar16_t*utf16String)
18 {
19 
20 if(mbBuffer==NULL||utf16String==NULL)
21 return0;
22 
23 mbstate_tstate={};
24 
25 size_tmbIndex=0;
26 
27 for(intutf16Index=0;utf16String[utf16Index]!=u'\0';utf16Index++)
28 
29 {
30 
31 constsize_tlength=c16rtomb(&mbBuffer[mbIndex],utf16String[utf16Index],&state);
32 
33 mbIndex+=length;
34 
35 }
36 
37 mbBuffer[mbIndex]='\0';
38 
39 
40 returnmbIndex;
41 
42 }
43 
44  
45 
46 intmain(intargc,char*argv[])
47 
48 {
49 
50 char16_tch=u'';
51 
52 charchBuffer[64];
53 
54 mbstate_tstate={};
55 
56 size_tlength=c16rtomb(chBuffer,ch,&state);
57 
58 chBuffer[length]='\0';
59 
60 printf("TheUTF-8characterlengthis:%zu,andthecharacteris:%s\n",length,chBuffer);
61  
62 constchar*utf8Str=u8"你好,世界。";
63 
64 printf("TheUTF-8stringis:%s\n",utf8Str);
65 
66 constchar16_t*utf16Str=u"你好,世界。";
67 printf("Theutf16stringlengthis:%zu\n",UTF16StrLen(utf16Str));
68 
69 length=UTF16ToUTF8(chBuffer,utf16Str);
70  
71 printf("TheUTF-8stringlengthis:%zu,andthecontentis:%s\n",length,chBuffer);
72 
73 printf("IftheconvertedUTF-8stringisequaltotheoriginalone?%s\n",strcmp(chBuffer,utf8Str)==0?"YES":"NO");
74 
75 }

 



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()。
---------------------
作者:xieyihua1994
來源:CSDN
原文:https://blog.csdn.net/xieyihua1994/article/details/51340354
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM