现在的位置: 首页 > 综合 > 正文

关于do…while();循环最后的分号。

2013年03月22日 ⁄ 综合 ⁄ 共 1034字 ⁄ 字号 评论关闭

首先,在C语言中,与while有关的两个循环结构定义如下:

1- while(条件) {...}

2- do{...} while(条件);

注意第2个循环最后的那个分号,为什么会有这个分号?因为第1个循环被作为一个整体,可以被编译器识别,而第2个循环,如果没有最后的分号,编译器就不知道while是修饰前面的语句,还是像第1个一样修饰后面的语句,这里的分号起到了断句,消除歧义的作用。

这个分号在Linux内核代码中成为了一种所谓的编程技巧。

在Linux内核中,可以看到这样的宏定义:

#define MACRO_NAME do{...}while(0)

这个宏执行的动作就是让{...}执行一次,可为什么非要这么定义? 看以下的情景:

如果宏定义如此: #define MACRO_NAME a=10;b=20;

if(...)

  MACRO_NAME;

else

  ...;

经过宏展开之后,变成:

if(...)

  a=10;b=20;;

else

  ...;

编译就会出错,因为找不到else匹配的if。这是因为我们宏定义的时候,没有把定义的语句做成一个整体,导致宏展开的时候影响了上下文的语法结构。

那么,你一定会想到为宏定义加上一对大括号:#define MACRO_NAME {a=10;b=20;}

展开之后,为:

if(...)

  {a=10;b=20};

else

  ...;

这仍然会出现else不匹配的问题,因为那个红色的分号仍然在大括号外面。而这个红色分号的存在是因为我们在使用宏的时候,仍然习惯于采用C语言的语法。于是,我们想到这么使用宏:

if(...)

  MACRO_NAME

else

  ...;

可这样,看起来似乎又不那么自然,起码表面上看不符合C语言的语法形式。

归根结底,最好的方式是,在出现宏调用的地方,把整个宏调用包括分号用一对大括号括起来。如下:

if(...)

  {MACRO_NAME;}

else

  ...;

这样,无论你在定义宏的时候是否加上分号,只要在调用宏的时候按照C语言的语法加上分号,就绝对不会出错,也不必在宏定义中

使用奇怪的do{...}while(0)循环了。

小结:

其实这种做法和采用do{...}while(0)定义宏的做法目的本质上一样,都是为了让编译器把宏调用处的分号与宏调用看作一个整体,只不过我是显式的

利用一对大括号直接括起来,而它是隐式的利用了C语言中的do{...}while(0);语法结构。采用do{...}while(0)的方式看起来有些古怪,但更简练。

抱歉!评论已关闭.