C99 (以前称为C9X )是ISO / IEC 9899:1999的非正式名称,在1999年推出,被ANSI于2000年3月采用。它是C编程语言标准的过去版本。 它扩展了以前的版本( C90 ),增加了语言和标准库的新功能,并帮助实现更好地利用可用的计算机硬件,如IEEE 754-1985浮点运算和编译器技术,最主要的增强在数值处理上。 2011年发布的C编程语言标准的
C11版本取代了C99。
信息介绍
在
ANSI的标准确立后,
C语言的规范在一段时间内没有大的变动,然而
C++在自己的标准化创建过程中继续发展壮大。《标准修正案一》在1994年为
C语言创建了一个新标准,但是只修正了一些
C89 标准中的细节和增加更多更广的国际字符集支持。不过,这个标准引出了1999年ISO 9899:1999的发表。它通常被称为C99。C99被ANSI于2000年3月采用。
但是各个公司对C99的支持所表现出来的兴趣不同。当GCC和其它一些商业编译器支持C99的大部分特性的时候,
微软和
Borland却似乎对此不感兴趣。
C99是在C89/90的基础上发展起来的,增加了基本数据类型、关键字和一些
系统函数等。
C99有一部分是对于增加了宽字符集,还加入了一些
库函数,是继C89标准之后的第二个C语言官方标准。第一个
C++语言官方标准C++98标准,就是基于C89编写的,因此C99标准新增的语法特性在C++的
编译器中就或多或少地支持了,而完全或几乎完全支持C99标准的主流编译器有:
GCC、
Clang、
Intel C++ Compiler等。另外,
Visual Studio2013也部分支持了C99语法特征。
C99标准的草案是免费的。
历史
ANSI于1989年制定了C编程语言的官方标准,并于1990年成为国际标准,C语言规范在一段时间内保持相对静态,而C ++继续发展,主要是在其自身的标准化工作中。规范修正案1在1995年为C制定了一个新标准,但只是为了纠正1989年标准的一些细节,并为国际字符集增加了更广泛的支持。该标准在20世纪90年代后期进行了进一步修订,导致1999年出版了ISO / IEC 9899:1999,并于2000年5月作为
ANSI标准工作组维护。
新特性
在
ANSI标准化发布了C89标准以后,
C语言的标准在一段相当的时间内都保持不变,尽管C++继续在改进。(实际上,Normative Amendment1在1995年已经开发了一个新的C语言版本(即C95)。但是这个版本很少为人所知。)标准在90年代才经历了改进,这就是ISO/IEC 9899:1999(1999年出版)。这个版本就是通常提及的C99。
在C89或者ANSIC的基础上,C99增加了如下特性。
增加restrict指针
C99中增加了适用于指针的
restrict 类型修饰符,它是初始访问指针所指对象的惟一途径,因此只有借助
restrict 指针表达式才能访问对象。
restrict 指针主要用做函数形参,或者指向由
malloc( ) 函数所分配的内存变量。
restrict 数据类型不改变程序的语义。
inline(内联)关键字
内联函数除了保持
结构化和函数式的定义方式外,还能使
程序员写出高效率的代码。如函数在代码内进行内联扩展,则执行代码时,函数与参数不需进栈与退栈,各种
寄存器内容不需保存与恢复。
新增数据类型
_Bool:值是0或1,C99中增加了用来定义
bool,
true以及
false 宏的
头文件< stdbool. h>,以便程序员能够编写同时兼容于C与C++的
应用程序,在编写新的应用程序时,应该使用< stdbool. h >
头文件的 bool 宏。
_Complex and _ lmaginary:C99 标准中定义的复数类型如下:
头文件中定义了 Complex 和 lmaginary 宏,并将它们扩展为 _Complex 和_Imaginary,因此在编写新的应用程序时,应该使用< stdbool.h >头文件中的 complex 和 imaginary 宏。 long long int:C99标准中引进了long long int ( - ( 2e63- 1)至 2e63 - 1) 和 unsigned longlong int (0至2e64 - 1),long long int 能够支持的整数长度为64位。
对数组的增强
可变长数组(VLA):C99中,程序员声明数组时,数组的维数可以由任意有效的
整型表达式确定,包括只在运行时才能确定其值的表达式,这类数组就叫做
可变长数组。但是只有局部数组才可以是变长的。可变长数组的维数在数组生存期内是不变的,也就是说,
可变长数组不是动态的。可以变化的只是数组的大小。可以使用*来定义不确定长的
可变长数组。
单行注释
字符//引入包含直到(但不包括)新换行符的所有多字节字符的
注释,除非//字符出现在
字符常量、
字符串文字或注释中。
分散代码与声明
C
编译器接受关于
可执行代码的混合类型声明,如以下示例所示:
预处理程序的修改
(1)具有可变数目的参数的宏。C
编译器接受以下形式的#define
预处理程序指令:
如果宏定义中的identifier__list以
省略号结尾,则意味着调用中的参数比
宏定义中的参数(不包括省略号)多;否则,
宏定义中参数的数目(包括由预处理标记组成的参数)与调用中参数的数目匹配。对于在其参数中使用省略号表示法的
#define预处理指令,在其替换列表中使用
标识符__ VA_ ARGS__。
(2)_ Pragma 操作符。
_Pragma ( string - literal )形式的一元操作符表达式处理如下:
(3)内部编译指令。
STDC FP_ CONTRACTON/OFF/DEFAULT
若为ON,浮点
表达式被当做基于硬件方式处理的独立单元,默认值是定义的工具。
STDC FEVN ACCESSON/OFF/DEFAULT
告诉
编译程序可以访问浮点环境,默认值是定义的工具。
STDC CX_ LIMITED_ RANGEON/OFF/ DEFAULT
若值为ON,相当于告诉
编译程序某程序某些含有复数的公式是可靠的,默认是OFF。
(4)新增的内部宏。
for语句内的变量声明
C99中,程序员可以在
for语句的初始化部分定义一个或多个
变量,这些变量的作用域仅于本for语句所控制的循环体内。
C编译器接受作为for
循环语句中第一个
表达式的类型声明:
for循环的
初始化语句中声明的任何变量的作用域是整个循环(包括控制和迭代表达式)。
复合赋值
C99中,复合赋值中,可以指定对象类型的
数组、
结构或联合
表达式,当使用复合赋值时,应在括弧内指定类型,后跟由花括号围起来的
初始化列表;若类型为数组,则不能指定数组的大小,建成的对象是未命名的。
柔性数组结构成员
C99中,结构中的最后一个元素允许是未知大小的
数组,这就叫做柔性数组成员,但结构中的柔性数组成员前面必须至少一个其他成员。柔性数组成员允许结构中包含一个大小可变的数组,
sizeof返回的这种结构大小不包括柔性数组的内存,包含柔性数组成员的结构用
malloc( )函数进行内存的动态分配。并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
复合赋值初始化符
C99中,该特性对经常使用稀疏数组的
程序员十分有用,指定的
初始化符通常有两种用法:用于数组,以及用于
结构体和
共用体。
用于数组的格式:
其中,
index表示数组的下标,vol表示本
数组元素的初始化值,例如:
其中只有 x[0] 和 x[5] 得到了
初始化。这种方式不错,但是VC6对他不支持。
member-name(成员名称):对结构进行指定的初始化时,允许采用简单的方法对结构中的指定成员进行初始化。
例如:
其中,没有初始化k,对结构成员进行
初始化的顺序没有限制。
printf和scanf函数系列的增强
C99 中
printf( ) 和
scanf( ) 函数系列引进了处理 long long int 和
unsigned long long int 数据类型的特性。long long int类型的格式
修饰符是II,在
printf()和
scanf()函数中,II适用于d.i.o.u和x格式说明符。
另外,C99还引进了 hh
修饰符,当使用d,i,o,u和x格式说明符时,hh用于指定
char型参数,II和hh修饰符均可以用于n说明符。
格式修饰符a和A用在printf( )函数中时,结果将会输出
十六进制的
浮点数,格式如下:
[ - ]0xh, hhhhp + d
使用A格式
修饰符时,x和p必须是大小,A和a格式
修饰符也可以用在
scanf()函数中,用于读取浮点数,调用printf()函数时,允许在%f说明符前加上I
修饰符,即%If,但不起作用。
C99新增的库
C99新增的头文件和库:
_ func__ 预定义标识符
用于指出__func__ 所存放的函数名,类似于
字符串赋值。
幂等限定符
类型限定符:如果同一限定符在同一说明符
限定符列表中出现多次(无论直接出现还是通过一个或多个
typedef ),行为与该类型
限定符仅出现一次时相同。
static及数组声明符的限定符
关键字
static可以出现在函数声明符中参数的数组声明符中,表示
编译器至少可以假定许多元素将传递到所声明的函数中,使优化器能够作出以其他方式无法确定的假定。
C
编译器将数组参数调整为
指针,因此void foo(int a[ ])与void foo(int *a)相同。
如果您指定void foo(int * restrict a);等类型限定符,则C编译器使用实质上与声明限定指针相同的数组语法void foo(int a [ restrict ]);表示它。
C编译器还使用
static限定符保留关于数组大小的信息。例如,如果指定voidfoo(int a[10]) ,则编译器仍将它表达为void foo (int *a)。 按以下所示使用
static限定符:void foo(int a [static 10]),让编译器知道指针a不是NULL,并且使用它可访问至少包含十个元素的整数数组。
设计
在大多数情况下,C99与C89向后兼容,但在某些方面它更严格。
特别是,缺少类型说明符的声明不再隐含假定的int。C标准委员会认为,编译器诊断无意中遗漏类型说明符比静默处理依赖于隐式int遗留代码更有价值。在实践中,编译器可能会显示警告,然后假设为int并继续翻译程序。
C99引入了几个新功能,其中许多已经在几个编译器中作为扩展实现:
C99标准的某些部分包含在当前版本的C ++标准中,包括整数类型,标题和库函数。可变长度数组不属于这些包含的部分,因为C ++的
标准模板库已经包含类似的功能。
关键字
数据类型关键字
1、char [tɑ:]:声明字符型变量或函数
2、double [dbl] :声明双精度变量或函数
4、float [flut] :声明
浮点型变量或函数
7、short [:t] :声明短整型变量或函数
8、signed:声明有符号类型变量或函数
10、union [ju:nin]:声明
共用体(联合)
数据类型11、unsigned [n'saind]:声明无符号类型变量或函数
12、void [vid] :声明函数无
返回值或无参数,声明无类型指针
控制语句关键字
A循环语句
3、while [wail] :
循环语句的循环条件
4、break [breik]:跳出当前循环
5、continue[kntinju:]:结束当前
循环,开始下一轮循环
B条件语句
1、if [if]: 条件语句
2、else [els] :
条件语句否定分支(与 if 连用)
3、goto:无条件跳转语句
C开关语句
1、switch [swit]:用于开关语句
2、case [keis]:开关语句分支
3、default [dif:lt]:开关语句中的“其他”分支
D返回语句
存储类型关键字
3、register [redist]:声明寄存器变量
其它关键字
1、const :声明只读变量
4、volatile [vltail]:说明
变量在程序执行中可被隐含地改变
C99新增
1、inline关键字用来定义一个类的
内联函数,引入它的主要原因是用它替代C中表达式形式的宏定义
引入原因:
C语言是一个效率很高的语言,这种宏定义在形式及使用上像一个函数,但它使用预处理器实现,没有了参数压栈,代码生成等一系列的操作
2、
restrict关键字只用于限定
指针;该关键字用于告知
编译器,所有修改该指针所指向内容的操作全部都是基于(base on)该指针的,即不存在其它进行修改操作的途径;这样的后果是帮助
编译器进行更好的代码优化,生成更有效率的汇编代码。
3、_Bool关键字是用于表示布尔值。包含标准
头文件 stdbool.h 后,我们可以用 bool 代替 _Bool ,true 代替 1 ,false 代替 0 。
4、_Complexand_
Imaginary关键字C99标准中定义的
复数类型如下:float_Complex; float_Imaginary; double_Complex; double_Imaginary; long double_Complex; long double_Imaginary.
头文件中定义了
complex和
imaginary宏,并将它们扩展为_Complex和_Imaginary,因此在编写新的应用程序时,应该使用头文件中的complex和imaginary宏。
版本检测
标准宏__STDC_VERSION__定义为值199901L,表示C99支持可用。与C90的__STDC__宏一样,__STDC_VERSION__可用于编写将针对C90和C99编译器进行不同编译的代码,如此示例中确保在任何一种情况下都可以使用inline(通过在C90中将其替换为static以避免链接器错误) )。
实施
大多数C编译器至少支持C99中引入的一些功能。
从历史上看,
Microsoft在其Visual C ++工具中实现新C功能的速度很慢,而主要侧重于支持C ++标准的开发。然而,随着Visual C ++ 2013的引入,Microsoft实现了C99的有限子集,它在Visual C ++ 2015中进行了扩展。
未来的工作
自批准1999 C标准以来,标准工作组编写了技术报告,规定了对嵌入式处理,附加字符数据类型(
Unicode支持)和具有改进边界检查的库函数的改进支持。继续处理有关十进制
浮点,附加数学
特殊函数和其他
动态内存分配函数的技术报告。C和C ++标准委员会一直在协调
线程编程的规范。
C标准的下一版本
C11于2011年获得批准。C标准委员会采用的指导方针限制了现有实施尚未测试的新功能的采用。在开发内存模型方面付出了很多努力,以便阐明序列点并支持
线程编程。
后续标准
C11标准是 ISO/IEC 9899:2011 - Information technology -- Programming languages -- C 的简称,曾用名为C1X。
C11标准是C语言标准的第三版,前一个标准版本是
C99标准。2011年12月8日,
国际标准化组织(ISO)和
国际电工委员会(IEC) 旗下的C语言标准委员会(ISO/IEC JTC1/SC22/WG14)正式发布了C11标准。
C11标准的最终定稿的草案是免费开放的,为N1570,但是正式标准文件需要198
瑞士法郎。
相比C99的区别
1. 对齐处理
操作符 alignof,函数 aligned_alloc(),以及 头文件
。2. _Noreturn 函数标记,类似于
gcc的 __attribute__((noreturn))。例子:
3. _Generic
关键词,有点儿类似于
gcc 的 typeof。示例代码:
4. 静态断言( static assertions),_Static_assert(),在解释 #if 和 #
error 之后被处理。例子:
5. 删除了 gets() 函数,C99中已经将此
函数被标记为过时,推荐新的替代函数 gets_s()。
6. 新的 fopen() 模式,(“…x”)。类似
POSIX 中的 O_CREAT|O_EXCL,在文件锁中比较常用。
7. 匿名结构体/联合体。
8. 多线程支持,包括:_
Thread_local,
头文件 ,里面包含线程的创建和管理函数(比如 thrd_create(),thrd_exit()),mutex (比如 mtx_lock(),mtx_unlock())等等。10. 带
边界检查(Bounds-checking)的函数接口,定义了新的安全的函数,例如 fopen_s(),strcat_s() 等等。
11. 改进的Unicode支持,新的头文件 等。实例代码:
12. 新增 quick_exit() 函数,作为第三种终止程序的方式,当
exit()失败时可以做最少的清理工作(deinitializition)。
14. 更多
浮点数处理的宏 (More macros for querying the characteristics of floating point types, concerning subnormal floating point numbers and the number of decimal digits the type is able to store)。
15. struct timespec 成为
time.h 的一部分,以及宏 TIME_UTC,函数 timespec_get()。