在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.初始化結構的時候允許對特定的元素賦值,形式爲:
- struct {int a[3],b;} foo[]
= {
[0].a
= {1},
[1].a
= 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。
例
- _Bool b1, b2;
- b1 = 99;
- b2 = -99;
打印b1, b2的值都將爲1(true)。
包含stdbool.h後,可以直接用bool代替_Bool,同時也可以使用true和false表示真和假。
stdbool.h內容如下:
- #ifndef _STDBOOL_H
- #define _STDBOOL_H
- #ifndef __cplusplus
- #define bool _Bool
- #define true 1
- #define false 0
- #else /* __cplusplus
*/
- /* Supporting
in C++
is a GCC extension.
*/
- #define _Bool bool
- #define bool bool
- #define false
false
- #define true
true
- #endif /* __cplusplus
*/
- /* Signal that all the definitions are present.
*/
- #define __bool_true_false_are_defined 1
- #endif /* stdbool.h
*/
_Complex, _Imaginary:複數類型和虛數類型,C99提供了三種複數類型和虛數類型:float
_Complex,double _Complex,long double _Complex和float _Imaginary,double _Imaginary,以及 long double _Imaginary。複數類型包括一個實部和一個虛部,虛數類型沒有實部,只有虛部。
例:
- #include <complex.h>
- double _Complex x = 5.2;
/* 實部等於 5.2,虛部爲 0
*/
- double _Complex y = 5.0
* i;
/* 實部爲 0,虛部爲 5.0
*/
- double _Complex z = 5.2 – 5.0
* i;
/* 實部爲 5.2,虛部爲 5.0
*/
同樣在程序中包含complex.h後,可以用 complex來代表 _Complex,用imaginary來代表 _Imaginary,以及用 I來代表虛數單位 i,也就是 -1的平方根。
complex.h內容如下
- #ifndef _COMPLEX_H
- #define _COMPLEX_H 1
- #include <features.h>
- /*
Get general and ISO C99 specific information.
*/
- #include <bits/mathdef.h>
- __BEGIN_DECLS
- /* We might need
to add support for more compilers here. But since ISO
- C99 is out hopefully all maintained compilers will soon provide the data
- types `float complex'
and `double complex'.
*/
- #if __GNUC_PREREQ
(2, 7)
&&
!__GNUC_PREREQ (2, 97)
- # define _Complex __complex__
- #endif
- #define complex _Complex
- /* Narrowest imaginary unit. This depends
on the floating-point
- evaluation method.
- XXX This probably has to go into a gcc related file.
*/
- #define _Complex_I (__extension__ 1.0iF)
- /* Another more descriptive name
is `I'.
- XXX Once we have the imaginary support switch this
to _Imaginary_I.
*/
- #undef I
- #define I _Complex_I
- /* The file
<bits/cmathcalls.h> contains the prototypes
for all the
- actual math functions. These macros are used
for those prototypes,
- so we can easily declare each
function as both `name'
and `__name',
- and can declare the float versions `namef'
and `__namef'.
*/
- #define __MATHCALL(function, args)
\
- __MATHDECL (_Mdouble_complex_,function, args)
- #define __MATHDECL(type,
function, args)
\
- __MATHDECL_1(type,
function, args);
\
- __MATHDECL_1(type, __CONCAT(__,function),
args)
- #define __MATHDECL_1(type,
function, args)
\
- extern type __MATH_PRECNAME(function) args __THROW
- #define _Mdouble_ double
- #define __MATH_PRECNAME(name) name
- #include <bits/cmathcalls.h>
- #undef _Mdouble_
- #undef __MATH_PRECNAME
- /*
Now the float versions.
*/
- #ifndef _Mfloat_
- # define _Mfloat_ float
- #endif
- #define _Mdouble_ _Mfloat_
- #ifdef __STDC__
- # define __MATH_PRECNAME(name) name##f
- #else
- # define __MATH_PRECNAME(name) name/**/f
- #endif
- #include <bits/cmathcalls.h>
- #undef _Mdouble_
- #undef __MATH_PRECNAME
- /*
And the long double versions. It
is non-critical
to define them
- here unconditionally since `long double'
is required in ISO C99.
*/
- #if (__STDC__
- 0 || __GNUC__
- 0)
\
- &&
(!defined __NO_LONG_DOUBLE_MATH
\
- || defined __LDBL_COMPAT
\
- ||
!defined _LIBC)
- # if defined __LDBL_COMPAT
|| defined __NO_LONG_DOUBLE_MATH
- # undef __MATHDECL_1
- # define __MATHDECL_1(type,
function, args)
\
- extern type __REDIRECT_NTH(__MATH_PRECNAME(function), args,
function)
- # endif
- # ifndef _Mlong_double_
- # define _Mlong_double_ long double
- # endif
- # define _Mdouble_ _Mlong_double_
- # ifdef __STDC__
- # define __MATH_PRECNAME(name) name##l
- # else
- # define __MATH_PRECNAME(name) name/**/l
- # endif
- # include <bits/cmathcalls.h>
- #endif
- #undef _Mdouble_
- #undef __MATH_PRECNAME
- #undef __MATHDECL_1
- #undef __MATHDECL
- #undef __MATHCALL
- __END_DECLS
restrict:用來限定指針,表明指針是訪問一個數據對象的唯一且初始化對象。作用是告訴編譯器除了該指針,其他任何指針都不能對所指向的數據進行存取,以便編譯器優化代碼。
inline:內聯函數,是爲了解決C 預處理器宏存在的問題所提出一種解決方案,用來提高函數使用效率。內聯函數使用inline關鍵字定義,並且函數體和申明必須結合在一起, 否則編譯器將他作爲普通函數對待。
- inline int function(int n);
- inline int function(int n)
- {
- return ((n%2)?1:0);
- }
內聯函數把代碼也加放入了符號列表中,避免了頻繁調用函數對棧帶來的消耗,達到優化代碼的作用。所以內聯函數本身不能太複雜。GCC對inline做了自己的擴展。
參考資料:
維基百科.C語言
關於C語言中的Complex(複數類型)和imaginary(虛數類型)
也談C語言的restrict類型修飾符
C語言inline詳細講解
理解內聯函數inline在C中的使用
如有錯誤請指正!
謝謝!