C语言常常让人觉得它能表达的东西很有限。它没有像一级函数和模式匹配这样的高级特性。但是C非常简单,并且仍然有一些非常有用的语法技巧和特性,但鲜为人知。1、指定初始化很多人都知道静态初始化数组是这样的:intfibs[]={1,1,2,3,5};C99标准实际上支持一种更直观、更简单的方式来初始化每个不同类型的集合数据(例如:结构、联合和数组)。二、数组我们可以指定数组的元素来初始化。这非常有用,尤其是当我们需要根据一组#define来保持某种映射关系同步更新时。我们来看一组错误码的定义,如:/*Entriesmaynotcorrespondtoactualnumbers。省略了一些条目。*/#defineEINVAL1#defineENOMEM2#defineEFAULT3/*...*/#defineE2BIG7#defineEBUSY8/*...*/#defineECHILD12/*...*/现在,假设我们想为每个错误代码提供一个错误描述字符串。为了保证数组保持最新的定义,无论对头文件进行任何修改或添加,我们都可以使用这个数组指定的语法。char*err_strings[]={[0]="Success",[EINVAL]="Invalidargument",[ENOMEM]="Notenoughmemory",[EFAULT]="Badaddress",/*...*/[E2BIG]="参数列表太长",[EBUSY]="设备或资源忙",/*...*/[ECHILD]="没有子进程"/*...*/};静态分配足够的空间,并保证最大索引合法,同时将特殊索引初始化为指定值,其余索引初始化为0。三、结构和联合初始化数据非常有用结构和联合的字段名称。假设我们定义:structpoint{intx;inty;intz;}然后我们像这样初始化structpoint:structpointp={.x=3,.y=4,.z=5};当我们不想把所有的字段都初始化为0时,这种方式可以很方便的在编译时生成一个结构体,而无需调用初始化函数。对于联合,我们可以使用相同的方法,只是我们只初始化一个字段。4.宏列表C中一个惯用的方法是有一个命名实体列表,需要为它们各自创建一个函数,对它们分别进行初始化,并在不同的代码模块中扩展它们的名称。这在Mozilla的源代码中被大量使用,那是我学会这个技巧的时候。例如,在我去年夏天从事的项目中,我们有一个为每个命令标记的宏列表。它是这样工作的:#defineFLAG_LIST(_)\_(InWorklist)\_(EmittedAtUses)\_(LoopInvariant)\_(Commutative)\_(Movable)\_(Lowered)\_(Guard)它定义了一个FLAG_LIST宏,这个宏有一个参数叫_,它本身就是一个宏,可以调用列表中的每一个参数。一个实际使用的例子可能更直观的说明问题。假设我们定义了一个宏DEFINE_FLAG,比如:#defineDEFINE_FLAG(flag)flag,enumFlag{None=0,FLAG_LIST(DEFINE_FLAG)Total};#undefDEFINE_FLAG扩展FLAG_LIST(DEFINE_FLAG)以获得以下代码:enumFlag{None=0,DEFINE_FLAG(InWorklist)DEFINE_FLAG(EmittedAtUses)DEFINE_FLAG(LoopInvariant)DEFINE_FLAG(Commutative)DEFINE_FLAG(Movable)DEFINE_FLAG(Lowered)DEFINE_FLAG(Guard)Total};然后,对每个参数展开DEFINE_FLAG宏,所以我们得到枚举如下:enumFlag{None=0,InWorklist,EmittedAtUses,LoopInvariant,Commutative,Movable,Lowered,Guard,Total};接下来,我们可能需要定义一些访问函数,以便更好地使用标志列表:#defineFLAG_ACCESSOR(flag)\boolis##flag()const{\returnhasFlags(1<
