在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 的 ,定义一些标准长度的 int 的 ,定义复数的 ,定义宽字符的 ,类似于泛型的数学函数 , 浮点数相关的 。 在 增加了 va_copy 用于复制 ... 的参数。 里增加了 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中的使用
如有错误请指正!
谢谢!
阅读(1166) | 评论(0) | 转发(0) |