-- TOC --
据牛人说,这种结构定义的macro,是唯一正确的;在某些场景下,这种结构可以避免使用goto,逻辑也非常清晰。
比如:
#define ERRBUF_SIZE 64
#define _PERROR \
do { \
char errbuf[ERRBUF_SIZE] = {0}; \
sprintf(errbuf, "%s:%d", __FILE__, __LINE__); \
perror(errbuf); \
} while(0)
_PERROR
可以直接被当做一个inline的函数使用(后面带上分号),而且因为用了do {...} while(0)
这样的代码结构定义,这个macro在任何C语言结构中,都可以正确地被展开。
这个结构还使用了C语言的一个特性,即在一个{}
结构中,可以定义变量,变量名称与外面的变量无关,变量在这个结构结束的时候消失。
只有这种结构的macro function才适用任何C语言结构,保证没错!
恰当的使用goto是OK的!但如果实在不想用,可以这样:
int foo(){
somestruct *ptr = malloc(...);
do{
dosomething...;
if(error)
break;
dosomething...;
if(error)
break;
dosomething...;
}while(0);
free(ptr);
return 0;
}
这里将函数主体部分用do{...}while(0)
结构包含起来,使用break来代替goto,后续的清理工作在while之后,现在既能达到同样的效果,而且代码的可读性、可维护性都要比上面的goto代码好的多了。
下面这个case,将前面说的两点结合了起来,实现了一个LOG macro接口,同时输入到屏幕以及记录日志到文件:
$ cat test.c
#include <stdio.h>
#include <string.h>
#define _LOGFILE "xyz_log.txt"
#define _LOG(x, ...) \
do { \
FILE *fp = fopen(_LOGFILE, "a"); \
if (fp == NULL) { \
fprintf(stderr, "open " _LOGFILE " failed.\n"); \
break; \
} \
fprintf(fp, x, ##__VA_ARGS__); \
fclose(fp); \
printf(x, ##__VA_ARGS__); \
} while(0)
int main(void){
_LOG("abc""123""\n");
_LOG("int:%d float:%f\n", 1, 2.12345);
_LOG("do while and break is good %d %f\n", 1, 2.12345);
return 0;
}
$ gcc -Wall -Wextra test.c -o test
$ ./test
abc123
int:1 float:2.123450
do while and break is good 1 2.123450
$ cat xyz_log.txt
abc123
int:1 float:2.123450
do while and break is good 1 2.123450
上面这段代码,在使用的时候,还是有不方便的地方,比如文件名的指定,也不支持线程安全。
我后来又写了一个log函数接口,实现可同时输出到屏幕和文件,不再使用macro的方式,可以灵活指定文件,以及线程安全:同时输出到屏幕和文件的log接口
可以定义一套新的变量,用break可以实现跳出,通过赋值可以实现传出参数。但为什么要这么做呢?
本文链接:https://cs.pynote.net/sf/c/202112261/
-- EOF --
-- MORE --