#define+do{} while(0)+peeror的思考
来源:互联网 发布:通达信的行情软件 编辑:程序博客网 时间:2024/06/06 09:48
今天看到这样一个程序,还挺有意思,感觉里面知识点挺多的,就想着复习复习!!
#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
- #define+do{} while(0)+peeror的思考
- #define XXX do{...}while(0)
- #define XXX do{...}while(0)
- #define do{}while(0)妙用
- C语言中宏定义(#define)时do{...}while(0)的价值
- define do{} while(0) 用法妙用
- do{}while(0)的使用(COPY)
- do...while(0)的妙用(转)
- (赚)do while(0)的用法
- #define st(x) do { x } while (__LINE__ == -1)的意义(转)
- #define MACRO_NAME(para) do{macro content}while(0)
- do{}while(0)的意义
- do/while(0)的妙用
- do/while(0)的妙用
- do...while(0)的用法
- do/while(0)的妙用
- do...while(0)的妙用
- do/while(0)的妙用
- JSON中get()和opt()的区别
- 打开Android Studio的时候报error: cannot connect to daemon错误
- 从源码带看Volley的缓存机制
- 立委科普:语言学算法是 deep NLP 绕不过去的坎儿
- Linux操作系统文件系统基础知识详解
- #define+do{} while(0)+peeror的思考
- LeetCode Max Points on a Line
- Centos7配置更新国内yum源
- Node.js + Mongodb 建站学习历程1
- android图片处理的工具代码
- WebView和JavaScrip交互基础
- LayoutInflater的inflate函数用法详解
- cc1: out of memory allocating 3355443200 bytes after a total of 610304 bytes
- 基于c++实现的几种排序算法