好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

实用C语言技巧

实用C语言技巧

C语言常常让人觉得它所能表达的东西非常有限。它不具有类似第一级函数和模式匹配这样的高级功能。但是C非常简单,并且仍然有一些非常有用的语法技巧和功能,只是没有多少人知道罢了。

指定的初始化

很多人都知道像这样来静态地初始化数组:

 int  fibs[] = { 1 ,  1 ,  2 ,  3 ,  5 };

C99标准实际上支持一种更为直观简单的方式来初始化各种不同的集合类数据(如:结构体,联合体和数组)。

数组

我们可以指定数组的元素来进行初始化。这非常有用,特别是当我们需要根据一组#define来保持某种映射关系的同步更新时。来看看一组错误码的定义,如:

 /*   Entries may not correspond to actual numbers. Some entries omitted.   */ 
 #define  EINVAL 1
 #define  ENOMEM 2
 #define  EFAULT 3
 /*   ...   */ 
 #define  E2BIG  7
 #define  EBUSY  8
 /*   ...   */ 
 #define  ECHILD 12
 /*   ...   */ 

现在,假设我们想为每个错误码提供一个错误描述的字符串。为了确保数组保持了最新的定义,无论头文件做了任何修改或增补,我们都可以用这个数组指定的语法。

 char  *err_strings[] =  {
         [  0 ] =  "  Success  "  ,
    [EINVAL]  =  "  Invalid argument  "  ,
    [ENOMEM]  =  "  Not enough memory  "  ,
    [EFAULT]  =  "  Bad address  "  ,
      /*   ...   */  
    [E2BIG ]  =  "  Argument list too long  "  ,
    [EBUSY ]  =  "  Device or resource busy  "  ,
      /*   ...   */  
    [ECHILD]  =  "  No child processes  " 
     /*   ...   */  
}; 

这样就可以静态分配足够的空间,且保证最大的索引是合法的,同时将特殊的索引初始化为指定的值,并将剩下的索引初始化为0。

宏列表

C中的一个惯用方法,是说有一个已命名的实体列表,需要为它们中的每一个建立函数,将它们中的每一个初始化,并在不同的代码模块中扩展它们的名字。这在 Mozilla的源码中经常用到,我就是在那时学到这个技巧的。例如,在我去年夏天工作的那个项目中,我们有一个针对每个命令进行标记的宏列表。其工作方 式如下:

 #define  FLAG_LIST(_)                   \ 
    _(InWorklist)                      \
    _(EmittedAtUses)                   \
    _(LoopInvariant)                   \
    _(Commutative)                     \
    _(Movable)                         \
    _(Lowered)                         \
    _(Guard) 

它定义了一个FLAG_LIST宏,这个宏有一个参数称之为 _ ,这个参数本身是一个宏,它能够调用列表中的每个参数。举一个实际使用的例子可能更能直观地说明问题。假设我们定义了一个宏DEFINE_FLAG,如:

 #define  DEFINE_FLAG(flag) flag,
    enum   Flag {
       None  =  0  ,
       FLAG_LIST(DEFINE_FLAG)
       Total
   };
  #undef  DEFINE_FLAG

对FLAG_LIST(DEFINE_FLAG)做扩展能够得到如下代码:

 enum   Flag {
        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宏,这样我们就得到了enum如下:

 enum   Flag {
        None  =  0  ,
        InWorklist,
        EmittedAtUses,
        LoopInvariant,
        Commutative,
        Movable,
        Lowered,
        Guard,
        Total
    }; 

接着,我们可能要定义一些访问函数,这样才能更好的使用flag列表:

 #define  FLAG_ACCESSOR(flag) \
 bool   is ##flag()  const   {\
      return  hasFlags( 1  <<  flag);\
}\
  void   set  ##flag() {\
    JS_ASSERT( !hasFlags( 1  <<  flag));\
    setFlags(  1  <<  flag);\
}\
  void   setNot##flag() {\
    JS_ASSERT(hasFlags(  1  <<  flag));\
    removeFlags(  1  <<  flag);\
}
 
FLAG_LIST(FLAG_ACCESSOR)
  #undef  FLAG_ACCESSOR

一步步的展示其过程是非常有启发性的,如果对它的使用还有不解,可以花一些时间在gcc –E上。

 http://www.cnblogs.com/pd520/archive/2013/02/04/2891553.html

 

分类:  C/C++

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于实用C语言技巧的详细内容...

  阅读:39次