C99标准的新特性
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C99标准的新特性
C语⾔标准的发展
C语⾔的发展历史⼤致上分为4个阶段:Old Style C、C89、C99和C11.
C89是最早的C语⾔规范,于1989年提出,1990年先由ANSI(美国国家标准委员会,American National Standards Institute)推出ANSI版本,后来被接纳为ISO国际标准(ISO/IEC9899:1990),因⽽有时也称为C90,最经典的C语⾔教材[K&R]就是基于这个版本的,C89是⽬前最⼴泛采⽤的C语⾔标准,⼤多数编译器都完全⽀持C89,C99(ISO/IEC9899:1999)是在1999年推出的,加⼊了许多新的特性,但⽬前仍没有得到⼴泛⽀持,在C99推出之后相当长的⼀段时间⾥,连gcc也没有完全实现C99的所有特性。
2011年12⽉8号,ISO 发布了新的 C 语⾔的新标准——C11,之前被称为C1X,官⽅名称 ISO/IEC 9899:2011。
现在介绍⼀下C99相对于C89或者ANSI C的新特性:
1.复数(complex)
complex.h是C标准函数库中的头⽂件,提供了复数算术所需要的宏定义与函数声明。
#define complex _Complex
#define _Complex_I ((const float _Complex)__I__)
#define I _Complex_I
C99规定了关键字_Complex。
因⽽有3种复数类型:
double _Complex
float _Complex
long double _Complex
次序不是必须遵守的,⽐如float _Complex也可以写成_Complex float。
_Complex_I扩展为类型为const float _Complex的常量值,其值为虚数单位。
C99规定complex作为宏扩展为_Complex。
但C++未定义complex宏。
gcc仅⽀持complex type,不⽀持imaginary type。
因此宏I扩展
为_Complex_I。
<complex.h>⾥⾯还包含了不少⽀持复数的数学函数(c打头的就是):
1、ccos,csin,ctan,cacos,casin,catan:复数域内的三⾓函数,有对应的f和l版本。
2、ccosh,csinh,ctanh,cacosh,casinh,catanh:复数域内的双曲函数,有对应的f和l版本。
3、cexp,clog,cabs,cpow,csqrt:复数域内的指数、对数、绝对值、幂函数,有对应的f和l版本。
4、carg,cimag,creal,conj,cproj:获取象限⾓、虚数部分、实数部分、a=x及b=-y、Riemann球上的投影,有对应的f和l版本。
代码:
#include<stdio.h>
#include<complex.h>
int main()
{
double complex cmp = 1.3 + 2.3*I;
printf("%f + %fi\n", creal(cmp), cimag(cmp));
return 0;
}
2.指定初始化(Designated Initializers)
在初始化结构体和数组时,可以通过指定具体成员名或数组下标来赋初值
要指定数组的索引对应的值,可以在相应的元素值前使⽤‘[index] =’,index必须是常量表达式例如:
int a[6] = { [4] = 29, [2] = 15 };
等价于:
int a[6] = { 0, 0, 15, 0, 29, 0 };
还可以向下⾯这样初始化:
int a[10] = { [1] = 1, [8 ... 9] = 10 };
这样可以只初始化a[1], a[8], a[9]三个元素,其他元素的值为0,等价于:
int a[10] = {0, 1, 0, 0, 0, 0, 0, 0, 10, 10};
对于结构体,指定成员名初始化可以使⽤‘.fieldname=’,例如:
struct point { int x, y; };
接下来初始化:
struct point p = { .y = yvalue, .x = xvalue }; // 等价于 struct point p = { xvalue, yvalue };
还可以使⽤冒号:
struct point p = { y: yvalue, x: xvalue };
当然也可以⽤在union中:
union foo { int i; double d; };
union foo f = { .d = 4 };
3.变长数组(Variable Length Arrays)
C99允许可以定义⼀个长度为变量的数组(这个数组的长度可以到运⾏时才决定)
FILE *
concat_fopen (char *s1, char *s2, char *mode)
{
char str[strlen (s1) + strlen (s2) + 1];
strcpy (str, s1);
strcat (str, s2);
return fopen (str, mode);
}
也可以在结构体或是联合中使⽤VLA:
void foo (int n)
{
struct S { int x[n]; };
}
你可以使⽤alloca函数实现类似的功能,但是alloca函数并不是都实现,从另⼀⾓度⽽⾔,VLA更加的优秀
也可以使⽤VLA作函数参数:
struct entry
tester (int len, char data[len][len])
{
/* ... */
}
当然也可以后传len
struct entry
tester (int len; char data[len][len], int len) //注意分号
{
/* ... */
}
⽰例代码:
#include<stdio.h>
void func(int n)
{
int vla[n];
printf("%d\n", sizeof(vla));
}
int main()
{
func(4);
return 0;
}
4.单⾏注释
gcc⽀持像C++风格的注释,以‘//’开头直到⼀⾏的结束,很多其他⽀持C99的C编译器都⽀持,但是c99之前的版本有可能不⽀持柔性数组成员((Flexible Array Members)
5.柔性数组成员
参见《》⼀⽂
6.long long类型
C99⽀持64位整型,使⽤long long int 或使⽤unsigned long long int,将整型常量声明为long long int,在整数的后⾯加上‘LL’,若为unsigned long long int,则加上‘ULL’
7.inline函数
c/c++中的inline,使⽤在函数声明处,表⽰程序员请求编译器在此函数的被调⽤处将此函数实现插⼊,⽽不是像普通函数那样⽣成调⽤代码(申请是否有效取决于编译器)。
⼀般地说,这样作的优点是省掉了调⽤函数的开销;缺点则是可能会增加代所⽣成⽬标代码的尺⼨
实际上,即使没有⼿⼯指定inline函数,编译器⼀般还会选择⼀些代码量较⼩但使⽤频繁的函数作为inline函数,以此作为性能优化的途径之⼀。
和带参宏定义(Parameterized Macro)相⽐,具备以下优点:
参数类型检查:宏定义中所使⽤的参数仅仅是在宏定义中被替换,不进⾏任何的类型检查
返回值:宏定义中⽆法使⽤return返回
便于调试
⽰例代码:
static inline int
inc (int *a)
{
return (*a)++;
}
8.bool类型
记得以前都是⾃⼰写#define TRUE 1, #define FALSE 0 或者 enum boolean之类的宏,现在可以使⽤<stdbool.h>的bool类型啦
9.复合常量(Compound Literals)
简单来说复合常量就是允许你定义⼀个匿名的结构体或数组变量。
如:
struct foo {int a; char b[2];} structure;
structure = ((struct foo) {x + y, 'a', 0});
等价于:
{
struct foo temp = {x + y, 'a', 0};
structure = temp;
}
也可以创建⼀个数组:
char **foo = (char *[]) { "x", "y", "z" };
更多实例:
static struct foo x = (struct foo) {1, 'a', 'b'};
static int y[] = (int []) {1, 2, 3};
static int z[] = (int [3]) {1};
//等价于下⾯的代码:
static struct foo x = {1, 'a', 'b'};
static int y[] = {1, 2, 3};
static int z[] = {1, 0, 0};
10.for循环变量初始化(for loop intializers)
C99引⼊了C++中的for循环变量初始化⽅式:
for(int i = 0; i < 10; ++i) {
...;
}
除了写起来⽅便以外,循环变量的⽣存周期也被最⼩化了。
这也顺便杜绝了那种把循环变量带到循环外头继续⽤的恶习
11.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年第⼀次修订时引进,⽤于⽀持多字节和宽字节分类函数注意:还有⼀些新特性未总结进来,待充分理解实践之后将陆续补充。