超级炫酷的C语言技巧!
来源:百问科技
int fibs[] = {1, 1, 2, 3, 5};C99标准实际上支持一种更为直观简单的方式来初始化各种不同的集合类数据(如:结构体,联合体和数组)。
/* 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"/* ... */};
struct point {int x;int y;int z;}
然后我们这样初始化struct point:
struct point p = {.x = 3, .y = 4, .z = 5};当我们不想将所有字段都初始化为0时,这种作法可以很容易的在编译时就生成结构体,而不需要专门调用一个初始化函数。
对联合体来说,我们可以使用相同的办法,只是我们只用初始化一个字段。
#define FLAG_LIST(_) \_(InWorklist) \_(EmittedAtUses) \_(LoopInvariant) \_(Commutative) \_(Movable) \_(Lowered) \_(Guard)
#define DEFINE_FLAG(flag) flag,enum Flag {None = 0,FLAG_LIST(DEFINE_FLAG)Total};#undef 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};
enum Flag {None = 0,InWorklist,EmittedAtUses,LoopInvariant,Commutative,Movable,Lowered,Guard,Total};
#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上。
但是,我们可以利用预处理来生成代码,这些代码只有在某些条件成立时才会通过编译(最好是那种不做实际功能的命令)。有各种各样不同的方式都可以做到这一点,通常都是建立一个大小为负的数组或结构体。最常用的方式如下:
/* Force a compilation error if condition is false, but also produce a result* (of value 0 and type size_t), so it can be used e.g. in a structure* initializer (or wherever else comma expressions aren't permitted). *//* Linux calls these BUILD_BUG_ON_ZERO/_NULL, which is rather misleading. */#define STATIC_ZERO_ASSERT(condition) (sizeof(struct { int:-!(condition); }) )#define STATIC_NULL_ASSERT(condition) ((void *)STATIC_ZERO_ASSERT(condition) )/* Force a compilation error if condition is false */#define STATIC_ASSERT(condition) ((void)STATIC_ZERO_ASSERT(condition))
它的使用非常简单,如果任何某假设条件能够静态地检查,那么它就可以在编译时断言。例如,在上面提到的标志列表中,标志集合的类型为uint32_t,所以,我们可以做以下断言:
STATIC_ASSERT(Total <= 32)(void)sizeof(struct { int:-!(Total <= 32) })(void)sizeof(struct { int: 0 })(void)sizeof(struct { int: -1 } )评论
