转自:宏与分号
细节决定成败!
如果留心的话,可以看到 linux内核代码经常有这么奇怪的宏定义:
引用 #define wait_event(wq, condition) do { if (condition) break; __wait_event(wq, condition); } while (0)
上面的宏中,while(0) 后是没有分号的,而且这个宏的 do 里执行一次,那为什么要这么定义呢?
这是因为,在程序里使用宏时,我们按照会在语句的后面加个分号 ; ,如:
wait_event(wq,conditon);
展开后,成为:
引用 do { if (condition) break; __wait_event(wq, condition); } while (0);
由此可见,分号自己加上了。假如在宏定义中已在 while(0) 后添加了分号。那么对于在程序中,单独的调用这个宏,不管在宏的后面是否添加分号,那都是可以的;如果是添加了分号,那就是执行了一个空语句。
但是对于 if ... else ... 结构,情况就不一样了,像下面的程序:
引用 #include <stdio.h> int condition = 0; #define wait_condition / do { / if (condition == 10) / break; / condition++; / sleep(1); / } while (0); / int main() { int k = 1; if (k == 1) wait_condition; /*添加了分号编译会报错*/ else printf ("hello world/n"); printf ("%d/n", condition); return (0); }
编译报错
引用 [beyes@localhost programming]$ gcc -g temp.c -o temp.exe temp.c: 在函数‘main’中: temp.c:19: 错误:‘else’没有对应的‘if’
如果在程序中将 wait_condition;后的分号去掉,那就可以编译通过了,但这看上去就不符合 C 语言的表达式习惯。所以,在宏定义里的 while(0) 后不需要添加分号。
然而,不管宏里加不加分号,但在程序里如下使用,也不会出现问题:
引用
{wait_condition; }
将宏语句用大括号括起来,这样整个宏将被当成一个整体看待,所以也是正确的。
那为什么会定义 do ... while(0) 这样的形式呢?
原因是,这样做会让程序的看起来更加简洁清晰(在程序中使用大括号把一个单独的宏括起来多少总觉得有些碍眼)。
分割线上是原文。个人感觉分析的不够透彻,为此写下个人感想。
上代码,每段代码分为 源码 + 编译情况 + 预处理后的.i文件。所有代码均在Linux环境下实验
正确代码
#include <stdio.h> #include <stdlib.h> int condition = 0; #define wait_condition do { if (condition == 10) break; condition++; sleep(1); } while (0) int main() { int k = 1; wait_condition; if (k == 1) wait_condition; /*添加了分号编译会报错*/ else printf ("hello world/n"); printf ("%d/n", condition); return (0); } 编译OK # 1 "/usr/include/bits/stdlib-float.h" 1 3 4 # 952 "/usr/include/stdlib.h" 2 3 4 # 964 "/usr/include/stdlib.h" 3 4 # 3 "hello.c" 2 int condition = 0; # 13 "hello.c" int main() { int k = 1; do { if (condition == 10) break; condition++; sleep(1);} while (0); if (k == 1) do { if (condition == 10) break; condition++; sleep(1);} while (0); else printf ("hello world/n"); printf ("%d/n", condition); return (0); }
以下均为错误代码
#include <stdio.h> #include <stdlib.h> int condition = 0; #define wait_condition do { if (condition == 10) break; condition++; sleep(1); } while (0); int main() { int k = 1; wait_condition; if (k == 1) wait_condition; /*添加了分号编译会报错*/ else printf ("hello world/n"); printf ("%d/n", condition); return (0); } 编译报错 hello.c: In function ‘main’: hello.c:19:5: error: ‘else’ without a previous ‘if’ else ^ # 1 "/usr/include/bits/stdlib-float.h" 1 3 4 # 952 "/usr/include/stdlib.h" 2 3 4 # 964 "/usr/include/stdlib.h" 3 4 # 3 "hello.c" 2 int condition = 0; # 13 "hello.c" int main() { int k = 1; do { if (condition == 10) break; condition++; sleep(1);} while (0);; if (k == 1) do { if (condition == 10) break; condition++; sleep(1);} while (0);; else printf ("hello world/n"); printf ("%d/n", condition); return (0); }
#include <stdio.h> #include <stdlib.h> int condition = 0; #define wait_condition if (condition == 10) break; condition++; sleep(1); int main() { int k = 1; wait_condition; if (k == 1) wait_condition; /*添加了分号编译会报错*/ else printf ("hello world/n"); printf ("%d/n", condition); return (0); } 编译报错 hello.c: In function ‘main’: hello.c:7:9: error: break statement not within loop or switch break; ^ hello.c:14:5: note: in expansion of macro ‘wait_condition’ wait_condition; ^ hello.c:7:9: error: break statement not within loop or switch break; ^ hello.c:16:9: note: in expansion of macro ‘wait_condition’ wait_condition; /*添加了分号编译会报错*/ ^ hello.c:17:5: error: ‘else’ without a previous ‘if’ els # 1 "/usr/include/bits/stdlib-float.h" 1 3 4 # 952 "/usr/include/stdlib.h" 2 3 4 # 964 "/usr/include/stdlib.h" 3 4 # 3 "hello.c" 2 int condition = 0; int main() { int k = 1; if (condition == 10) break; condition++; sleep(1);; if (k == 1) if (condition == 10) break; condition++; sleep(1);; else printf ("hello world/n"); printf ("%d/n", condition); return (0); }
#include <stdio.h> #include <stdlib.h> int condition = 0; #define wait_condition if (condition == 10) break; condition++; sleep(1) int main() { int k = 1; wait_condition; if (k == 1) wait_condition; /*添加了分号编译会报错*/ else printf ("hello world/n"); printf ("%d/n", condition); return (0); } 编译报错 hello.c: In function ‘main’: hello.c:7:9: error: break statement not within loop or switch break; ^ hello.c:14:5: note: in expansion of macro ‘wait_condition’ wait_condition; ^ hello.c:7:9: error: break statement not within loop or switch break; ^ hello.c:16:9: note: in expansion of macro ‘wait_condition’ wait_condition; /*添加了分号编译会报错*/ ^ hello.c:17:5: error: ‘else’ without a previous ‘if’ else ^ # 1 "/usr/include/bits/stdlib-float.h" 1 3 4 # 952 "/usr/include/stdlib.h" 2 3 4 # 964 "/usr/include/stdlib.h" 3 4 # 3 "hello.c" 2 int condition = 0; int main() { int k = 1; if (condition == 10) break; condition++; sleep(1); if (k == 1) if (condition == 10) break; condition++; sleep(1); else printf ("hello world/n"); printf ("%d/n", condition); return (0); }
#include <stdio.h> #include <stdlib.h> int condition = 0; #define wait_condition if (condition == 10) return; condition++; sleep(1) int main() { int k = 1; wait_condition; if (k == 1) wait_condition; /*添加了分号编译会报错*/ else printf ("hello world/n"); printf ("%d/n", condition); return (0); } 编译报错 hello.c: In function ‘main’: hello.c:17:5: error: ‘else’ without a previous ‘if’ else # 1 "/usr/include/bits/stdlib-float.h" 1 3 4 # 952 "/usr/include/stdlib.h" 2 3 4 # 964 "/usr/include/stdlib.h" 3 4 # 3 "hello.c" 2 int condition = 0; int main() { int k = 1; if (condition == 10) return; condition++; sleep(1); if (k == 1) if (condition == 10) return; condition++; sleep(1); else printf ("hello world/n"); printf ("%d/n", condition); return (0); }
#include <stdio.h> #include <stdlib.h> int condition = 0; #define wait_condition if (condition == 10) return; condition++; sleep(1); int main() { int k = 1; wait_condition; if (k == 1) wait_condition; /*添加了分号编译会报错*/ else printf ("hello world/n"); printf ("%d/n", condition); return (0); } 编译报错 llo.c:17:5: error: ‘else’ without a previous ‘if’ else ^ # 1 "/usr/include/bits/stdlib-float.h" 1 3 4 # 952 "/usr/include/stdlib.h" 2 3 4 # 964 "/usr/include/stdlib.h" 3 4 # 3 "hello.c" 2 int condition = 0; int main() { int k = 1; if (condition == 10) return; condition++; sleep(1);; if (k == 1) if (condition == 10) return; condition++; sleep(1);; else printf ("hello world/n"); printf ("%d/n", condition); return (0); }
我给出的结论:
如果带参宏,宏体有判断。请一定要加上do while(0),而且不能再while(0)后面加;
这种情况报找不到if是因为多出来的那个;造成的
单独;表示一句话,他隔开了else
这种情况的找不到else不是由于;造成的
从这句话开始就隔断了else。
C认为什么是语句?
①int a=10; 这种有指令内容,有分号,是一条语句。
② ; 这种也是一句话,一条语句。只不过事空语句
说白了,C判断是不是语句实际上是在查 ;