Chinaunix首页 | 论坛 | 博客
  • 博客访问: 67786
  • 博文数量: 15
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2015-10-08 10:05
文章分类
文章存档

2016年(3)

2015年(12)

我的朋友
最近访客

分类: C/C++

2015-10-09 12:39:51

原文地址:C语言 C99新增关键字 作者:zehn_w

在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 的 ,定义一些标准长度的 int 的  ,定义复数的 ,定义宽字符的 ,类似于泛型的数学函数 , 浮点数相关的 。 在 增加了 va_copy 用于复制 ... 的参数。 里增加了 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中的使用

如有错误请指正!
谢谢!
阅读(1727) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~