今天看到这样一个程序,还挺有意思,感觉里面知识点挺多的,就想着复习复习!!
#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE);} while(0)
1. perror函数
2. exit函数以及EXIT_TAIURE
3. #define 与do{}while()函数的特殊结合
关于perror函数:
头文件: #include <stdio.h>(不可以掉了这个文件,因为perror就是在这个文件中)和 #include <stdlib.h>
定义函数
函数说明
范例
#include <errno.h>
运行结果
关于exit和EXIT_TAIURE
我们在main函数中通常用:return 0;来结束程序,返回一个值,但是这些仅仅是局限于非void的情况下,也就是 void main()中。但是如果把exit函数用在main函数中,不管main函数的返回值是不是void,exit都是有效,在(int main()的情况下,返回值等同于return)
exit用在子程序中,终结程序,跳回操作系统
只用exit(0)代表程序的正常退出,其余的参数皆表示程序的异常退出
如果main()在一个递归程序中,exit()仍然会终止程序;但return将
然而对于:EXIT_FALURE(在vc6.0中,它被定义于头文件stdio.h中)
#define EXIT_FALURE 0
#define EXIT_SUCESS 1
关于宏中使用do-while函数
一般我们都知道do-while函数基本上都用于循环中,但是在这里为什么要加入do while 0呢,不是也是执行一次吗,放在这里它有什么优势吗???我们知道define函数的简单用法是:定义一个常量,或者一个简单地语句,或者函数,都只是简单地往后面加一个分号(“;”),但是究竟多个顺序执行的语句如何跟define联系起来呢?它们又跟do-while有什么关系呢??
在define中定义一个可以执行多个函数的宏
第一种:
#define Sequence print1();print2();
然后我们的程序可能这样调用:
Sequence;
然后它的确是在预编译期就被这样的替换了:
print1();print2();
能达到我们的预期效果:但是如果我们的程序是这样的呢?
if(flag)
Sequence;
它就被替换成为了这样(就不是我们预期的那样了):
if(flag)
print1();
printf(2);
也就是说无论flag这个标志值是真的假的,print2()这个函数都会被执行了,
所以这是我们经常犯的错误,也是大家经常犯得错误了
第二种:
#define Sequence {print1();print2();}
可以看到跟第一种的区别仅仅是,将两个函数放在了大括号中,但是,这样真的可以吗??
Sequence;
这样子也是可以的,就是相当于这样:
{
print1();
print2();
};
从上面我们可以看到对程序的多个语句加上大括号(并且加上分号),是对整个程序没有影响的
但是,如果是放在if语句中呢?
if(flag)
Sequence();
else
printf("123");
可以知道,上面的程序被替换也就成了这样的:
if(flag)
{
print1();
print2();
};
else
printf("123");
这时,编译器就会报错,编译错误,大家可以看到这个结构已经不满足if-else结构了
但是,值得注意的是:
单独使用if语句是后面的分号可有可无,就是说:
if(flag)
{
print1();
print2();
};
等价与:
if(flag)
{
print1();
print2();
}
第三种:
使用do()-while(0)函数,构造后的宏定义不会受到大括号,分号的影响,基本上总是来按照我们的意愿行事
所以我们会这样写:
#define Sequence do { print1(); print2();}while(0)
现在,该函数的功能等价与前面两着的综合,do能确保大括号里的逻辑被执行,而while(0)确保里面的逻辑被执行一次,即和没有循环是一样的
所以当前这个语句在if中的话:
if (flag)
Sequence;
可以用这个来进行替换:
if (flag)
do { print1(); print2();}while(0);
同时,也等价与:
if(flag)
{
print1();
print2();
}
其次,
当然我们这里声明:
#define Sequence do { print1(); print2();}while(0)
上面这个语句和下面这个也是一样的,而且更容易出现
#define Sequence \
do \
{ print1(); \
print2(); \
} while(0)
所以我们才会在Linux内核和其它一些著名的C库中有许多使用do{...}while(0)的宏定义
2,消除goto语句对程序流的统一控制
有些函数中,在函数return之前,我们经常会进行一些收尾的工作,比如free掉一块函数开始的malloc内存,goto一直都是一个比较简单的方法
int foo()
{
somestruct* ptr = malloc(...);
dosomething...;
if(error)
{
goto END;
}
dosomething...;
if(error)
{
goto END;
}
dosomething...;
END:
free(ptr);
return 0;
}
但是,goto语句不符合软件工程的结构化,致使写的代码可能会难懂,所以这里也就被大部分人不提倡使用,取而代之的是do-while外加break;
int foo()
{
somestruct* ptr = malloc(...);
do{
dosomething...;
if(error)
{
break;
}
dosomething...;
if(error)
{
break;
}
dosomething...;
}while(0);
free(ptr);
return 0;
}
这里,我们用break代替goto完美的解决了上面的问题!!
3, 避免空宏引起的警告warning,为了避免warning我们采用这样的结构:
#define do{ }while(0)
参考:百度百科
http://blog.csdn.net/luoweifu/article/details/38563161
http://blog.csdn.net/ypist/article/details/7886209