C語言 C99新增關鍵字 2012

在ANSI的標準確立後,C語言的規範在一段時間內沒有大的變動,然而C++在自己的標準化建立過程中繼續發展壯大。《標準修正案一》在1994年爲C語言建立了一個新標準,但是隻修正了一些C89標準中的細節和增加更多更廣的國際字符集支持。不過,這個標準引出了1999年ISO 9899:1999的發表。它通常被稱爲C99。C99被ANSI於2000年3月採用。


在C99中包括的特性有:

1.增加了對編譯器的限制,比如源程序每行要求至少支持到 4095 字節,變量名函數名的要求支持到 63 字節(extern 要求支持到 31)。
2.增強了預處理功能。例如:
a.巨集支持取可變參數 #define Macro(...) __VA_ARGS__
b.使用巨集的時候,允許省略參數,被省略的參數會被擴展成空串。
c.支持 // 開頭的單行註釋(這個特性實際上在C89的很多編譯器上已經被支持了)
3.增加了新關鍵字 restrict, inline, _Complex, _Imaginary, _Bool支持 long long, long double _Complex, float _Complex 等類型
4.支持不定長的數組,即數組長度可以在運行時決定,比如利用變量作爲數組長度。聲明時使用 int a[var] 的形式。不過考慮到效率和實現,不定長數組不能用在全局,或 struct與 union 裏。
5.變量聲明不必放在語句塊的開頭,for 語句提倡寫成 for(int i=0;i<100;++i) 的形式,即i 只在 for 語句塊內部有效。
6.允許採用(type_name){xx,xx,xx} 類似於 C++ 的構造函數的形式構造匿名的結構體。
7.初始化結構的時候允許對特定的元素賦值,形式爲:
  1. struct {int a[3],b;} foo[] = { [0].a = {1}, [1].a = 2 };

  2. struct {int a, b, c, d;} foo = { .a = 1, .c = 3, 4, .b = 5} // 3,4 是對 .c,.d 賦值的
8.格式化字符串中,利用 \u 支持 unicode 的字符。
9.支持 16 進制的浮點數的描述。
10.printf scanf 的格式化串增加了對 long long int 類型的支持。
11.浮點數的內部數據描述支持了新標準,可以使用 #pragma 編譯器指令指定。
12.除了已有的 __line__ __file__ 以外,增加了 __func__ 得到當前的函數名。
13.允許編譯器化簡非常數的表達式。
14.修改了 / % 處理負數時的定義,這樣可以給出明確的結果,例如在C89中-22 / 7 = -3, -22 % 7 = -1,也可以-22 / 7= -4, -22 % 7 = 6。 而C99中明確爲 -22 / 7 = -3, -22 % 7 = -1,只有一種結果。
15.取消了函數返回類型默認爲 int 的規定。
16.允許 struct 定義的最後一個數組不指定其長度,寫做 [] 。
17.const const int i 將被當作 const int i 處理。
18.增加和修改了一些標準頭文件,比如定義 bool 的 <stdbool.h> ,定義一些標準長度的 int 的 <inttypes.h> ,定義複數的 <complex.h> ,定義寬字符的 <wctype.h> ,類似於泛型的數學函數 <tgmath.h>, 浮點數相關的 <fenv.h>。 在<stdarg.h> 增加了 va_copy 用於複製 ... 的參數。<time.h> 裏增加了 struct tmx ,對 struct tm 做了擴展。
19.輸入輸出對寬字符以及長整數等做了相應的支持。

但是各個公司對C99的支持所表現出來的興趣不同。當GCC和其它一些商業編譯器支持C99的大部分特性的時候,微軟和Borland卻似乎對此不感興趣。


在C99中新增了5個關鍵字:
_Bool:布爾類型,用來表示假,零表示假,非零表示真。所有非零的數賦值給布爾型變量,最終的值還是1。
  1. _Bool b1, b2;
  2. b1 = 99;
  3. b2 = -99;
打印b1, b2的值都將爲1(true)。
包含stdbool.h後,可以直接用bool代替_Bool,同時也可以使用true和false表示真和假。
stdbool.h內容如下:
  1. #ifndef _STDBOOL_H

  2.   #define _STDBOOL_H

  3.   #ifndef __cplusplus

  4.   #define bool _Bool

  5.   #define true 1

  6.   #define false 0

  7.   #else /* __cplusplus */

  8.   /* Supporting in C++ is a GCC extension. */

  9.   #define _Bool bool

  10.   #define bool bool

  11.   #define false false

  12.   #define true true

  13.   #endif /* __cplusplus */

  14.   /* Signal that all the definitions are present. */

  15.   #define __bool_true_false_are_defined 1

  16.   #endif /* stdbool.h */
_Complex, _Imaginary:複數類型和虛數類型,C99提供了三種複數類型和虛數類型:float _Complex,double _Complex,long double _Complex和float _Imaginary,double _Imaginary,以及 long double _Imaginary。複數類型包括一個實部和一個虛部,虛數類型沒有實部,只有虛部。
例:
  1. #include <complex.h>

  2. double _Complex x = 5.2; /* 實部等於 5.2,虛部爲 0 */

  3. double _Complex y = 5.0 * i; /* 實部爲 0,虛部爲 5.0 */

  4. double _Complex z = 5.2 – 5.0 * i; /* 實部爲 5.2,虛部爲 5.0 */
同樣在程序中包含complex.h後,可以用 complex來代表 _Complex,用imaginary來代表 _Imaginary,以及用 I來代表虛數單位 i,也就是 -1的平方根。
complex.h內容如下
  1. #ifndef _COMPLEX_H
  2. #define _COMPLEX_H 1

  3. #include <features.h>

  4. /* Get general and ISO C99 specific information. */
  5. #include <bits/mathdef.h>

  6. __BEGIN_DECLS

  7. /* We might need to add support for more compilers here. But since ISO
  8. C99 is out hopefully all maintained compilers will soon provide the data
  9. types `float complex' and `double complex'. */
  10. #if __GNUC_PREREQ (2, 7) && !__GNUC_PREREQ (2, 97)
  11. # define _Complex __complex__
  12. #endif

  13. #define complex _Complex

  14. /* Narrowest imaginary unit. This depends on the floating-point
  15. evaluation method.
  16. XXX This probably has to go into a gcc related file. */
  17. #define _Complex_I (__extension__ 1.0iF)

  18. /* Another more descriptive name is `I'.
  19. XXX Once we have the imaginary support switch this to _Imaginary_I. */
  20. #undef I
  21. #define I _Complex_I

  22. /* The file <bits/cmathcalls.h> contains the prototypes for all the
  23. actual math functions. These macros are used for those prototypes,
  24. so we can easily declare each function as both `name' and `__name',
  25. and can declare the float versions `namef' and `__namef'. */

  26. #define __MATHCALL(function, args) \
  27. __MATHDECL (_Mdouble_complex_,function, args)
  28. #define __MATHDECL(type, function, args) \
  29. __MATHDECL_1(type, function, args); \
  30. __MATHDECL_1(type, __CONCAT(__,function), args)
  31. #define __MATHDECL_1(type, function, args) \
  32. extern type __MATH_PRECNAME(function) args __THROW

  33. #define _Mdouble_ double
  34. #define __MATH_PRECNAME(name) name
  35. #include <bits/cmathcalls.h>
  36. #undef _Mdouble_
  37. #undef __MATH_PRECNAME

  38. /* Now the float versions. */
  39. #ifndef _Mfloat_
  40. # define _Mfloat_ float
  41. #endif
  42. #define _Mdouble_ _Mfloat_
  43. #ifdef __STDC__
  44. # define __MATH_PRECNAME(name) name##f
  45. #else
  46. # define __MATH_PRECNAME(name) name/**/f
  47. #endif
  48. #include <bits/cmathcalls.h>
  49. #undef _Mdouble_
  50. #undef __MATH_PRECNAME

  51. /* And the long double versions. It is non-critical to define them
  52. here unconditionally since `long double' is required in ISO C99. */
  53. #if (__STDC__ - 0 || __GNUC__ - 0) \
  54. && (!defined __NO_LONG_DOUBLE_MATH \
  55. || defined __LDBL_COMPAT \
  56. || !defined _LIBC)
  57. # if defined __LDBL_COMPAT || defined __NO_LONG_DOUBLE_MATH
  58. # undef __MATHDECL_1
  59. # define __MATHDECL_1(type, function, args) \
  60. extern type __REDIRECT_NTH(__MATH_PRECNAME(function), args, function)
  61. # endif

  62. # ifndef _Mlong_double_
  63. # define _Mlong_double_ long double
  64. # endif
  65. # define _Mdouble_ _Mlong_double_
  66. # ifdef __STDC__
  67. # define __MATH_PRECNAME(name) name##l
  68. # else
  69. # define __MATH_PRECNAME(name) name/**/l
  70. # endif
  71. # include <bits/cmathcalls.h>
  72. #endif
  73. #undef _Mdouble_
  74. #undef __MATH_PRECNAME
  75. #undef __MATHDECL_1
  76. #undef __MATHDECL
  77. #undef __MATHCALL

  78. __END_DECLS
restrict:用來限定指針,表明指針是訪問一個數據對象的唯一且初始化對象。作用是告訴編譯器除了該指針,其他任何指針都不能對所指向的數據進行存取,以便編譯器優化代碼。
inline:內聯函數,是爲了解決C 預處理器宏存在的問題所提出一種解決方案,用來提高函數使用效率。內聯函數使用inline關鍵字定義,並且函數體和申明必須結合在一起, 否則編譯器將他作爲普通函數對待。
  1. inline int function(int n);
  2. inline int function(int n)
  3. {
  4. return ((n%2)?1:0);
  5. }
內聯函數把代碼也加放入了符號列表中,避免了頻繁調用函數對棧帶來的消耗,達到優化代碼的作用。所以內聯函數本身不能太複雜。GCC對inline做了自己的擴展。

參考資料:
維基百科.C語言
關於C語言中的Complex(複數類型)和imaginary(虛數類型)
也談C語言的restrict類型修飾符
C語言inline詳細講解
理解內聯函數inline在C中的使用

如有錯誤請指正!
謝謝!
發佈了20 篇原創文章 · 獲贊 3 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章