C99标准新特性概览

C99新增关键字

关键字 含义
inline 用于指示编译器尽可能地将inline修饰的函数指令在被调用的地方展开
restrict 用于指针修饰,表明该指针是访问其管理数据的唯一方式
_Bool C99新增_Bool类型,用于表示布尔值,对应于逻辑值true和false
_Complex 复数类型
_Imaginary 虚数类型

新增特性概述

指定初始化

C99标准支持在初始化结构体和数组时,不需要一次性将所有的成员和内容都进行设置,可以通过指定具体的成员名称或数组下标进行初始化。

结构体的指定初始化

Linux内核代码普遍使用了指定初始化的方式来对结构体的特定成员进行赋初值,参考一个实例:

struct bus_type scsi_bus_type = 
{
    .name = "scsi",
    .match = scsi_bus_match,
    .uevent	 = scsi_bus_uevent,
};

使用指定初始化的方式后,可以只对特定的成员进行初始化,而忽略掉那些不相关的成员。另外,使用这种方式,也不需要再考虑结构体成员的定义顺序,并且成员和初始值的关联也更加清晰。

数组的指定初始化

数组定义时,允许通过指定数组下标来对特定的成员进行赋值,而其它未指定的成员则赋初值0:

int array[10] = 
{
    [0] = 4,
    [3] = 8,
}

for循环变量初始化

C99标准引入了C++中的for循环变量初始化方式,允许在for循环语句中定义循环局部变量使用,这避免了每次使用for循环语句时,都需要定义一个通常只会在for语句中使用的循环变量:

for (int index = 0; index < MAX_NUM; index++)
{
    ...
}

柔性数组

C99标准中,结构的最后一个元素允许是未知大小的数组,这个元素就被称为柔性数组成员。柔性数组成员允许结构体中包含一个大小可变的数组,其存储空间需要我们使用动态分配的方式产生,并且分配的内存的大小应该大于结构体的大小,以适应柔性数组的预期大小。

柔性数组的使用示例如下:

typedef struct synx_example_s
{
    int val;
    int zero_array[];
}synx_example_t;

在GCC扩展中,实现了类似的特性,只是在语法格式上和C99标准存在一些差异。GCC扩展允许结构的最后一个元素为长度为0的数组,又称零长数组。相同的示例,零长数组的实现如下:

typedef struct synx_example_s
{
   int val;
   int zero_array[0];      /* 最后一个元素为长度为零的数组 */
}synx_example_t;

可变参数宏

C99中规定宏可以像函数一样带有可变参数,比如

#define LOG(format, ...) fprintf(stdout, format, __VA_ARGS__)

GCC中同时支持如下的形式

#define LOG(format, args...) fprintf(stdout, format, args)

其用法和上面的基本一致,只是参数符号有变化.

有一点需要注意,上述的宏定义不能省略可变参数,尽管你可以传递一个空参数,这里有必要提到"##"连接符号的用法。

"##"的作用是对token进行连接,在上例中,format、VA_ARGS、args即是token,

如果token为空,那么不进行连接,所以允许省略可变参数(__VA_ARGS__和args),对上述变参宏做如下修改

#define LOG(format, ...)     fprintf(stdout, format, ##__VA_ARGS__)
#define LOG(format, args...) fprintf(stdout, format, ##args)

混合声明

在ANSI C标准中,局部变量声明必须要放在函数的首部,这是由历史原因造成。编译器在编译函数时,需要提前为函数预留堆栈空间,将局部变量放在首部便于编译器进行处理。但是C99现在支持混合声明,这意味着,你可以在函数实现的任何地方,声明你所需要的变量。

long long类型

ANSI C标准定义了long整型,long整型在32位系统上的长度为32位,在64位系统上则为64位,新标准添加的long long类型实现了在32位和64位系统上都为64位的整型数。

bool类型

C标准的一大缺憾就是没有定义布尔类型,导致在大部分软件中都基本需要自定义布尔类型使用。C99标准意识到了这个问题,新增加了_Bool关键字,用于定义布尔类型。至于布尔类型值的定义则置于新增的stdbool.h头文件中:

#ifdef __cplusplus
# define false false
# define true true
#else
# undef false
# define false 0
# undef true
# define true 1
#endif

固长类型头文件

由于历史原因,C语言中实现的整型数只保证了在不同硬件体系中的最小长度,因此在使用时,需要根据代码实际运行的平台来确定类型的长度,这导致代码非常不方便移植。C99标准通过增加固长类型头文件引入了固定长度的整型数。stdint.h文件定义的固长整数类型如下:

  • 8位整型数:int8_t,uint8_t
  • 16位整型数:int16_t,uint16_t
  • 32位整型数:int32_t,uint32_t
  • 64位整型数:int64_t,uint64_t

内联函数

C99标准新增inline关键字用于修饰函数,使用inline关键字修饰的函数则成为内联函数,编译器在编译时,会尝试将内联函数扩展到所有该函数的调用处,从而避免过多的对该函数调用的开销。但由于内联函数的代码指令会被扩展到被调用处,因此会增加目标文件的大小,所以需要谨慎使用内联语义。

被声明为inline的函数如果要实现内联,就必须在编译单元内可见。

行注释//

C99参考C++语言引入了很多的易用特性,相对于/**/注释方式,//在使用上要方便很多。不过,个人在此的建议是,不要混用两种注释方式,因为那看起来确实不协调。

变长数组

通常我们定义的数组,在编译时其长度已经是明确的,即运行期间数组长度不允许更改。C99标准则支持了不定长数组的定义,其允许我们使用变量来定义数组的长度。不过,这个特性不推荐使用,在此不多做说明。

相关参考

  • 《C标准手册》
  • 《C primer plus》

你可能感兴趣的:(#,万物皆可C,开发语言,后端)