首页 > 其他分享 >do-while(0)语句到底有什么用?

do-while(0)语句到底有什么用?

时间:2023-07-31 14:01:22浏览次数:26  
标签:语句 do goto int while printf


前言

在一个群里面看到一个人问,do-while(0)语句有什么用?do-while(0)这个程序最终结果不应该就是程序只跑一次,那么写和不写有什么区别呢?

do-while(0)在复杂宏定义上的优点

为什么需要复杂宏

(1)在讲解do-while(0)在复杂宏定义上的优点前,我先介绍一下复杂宏的好处。
(2)当我们看到一个宏定义非常复杂的时候,我们很自然而然的会想到,为啥不让他变成一个函数呢?在宏定义里面搞到这么花里胡哨的,不如直接定义一个函数来的方便。
(3)当我带着这么问题去询问了交流群之后,一个大佬马上给出了回复。
<1>他说他当年一个项目8位单片机,函数都不敢深入调用,好多都是写的宏函数。因为资源有限。
<2>大佬介绍到,他哪一款单片机,硬件堆栈,好像就7层,中断预留两层,有些c标准函数用两层堆栈,自己写的就限制在3-4层左右。因为堆栈的有限,怕因为函数的深入调用如果过于频繁或递归层数过深,可能导致栈空间不足,发生堆栈溢出。当栈空间不足以容纳新的栈帧时,程序会崩溃或异常终止。
<3>所以他们当年都是这样写代码

do-while(0)语句到底有什么用?_宏定义

优点介绍

(1)当我们在编写业务逻辑的时候,可能可能需要定义一个比较复杂的宏。如下

#define  fun printf("hello"); printf("world")
int main()
{
	fun;
	return 0;
}

(2)在这个宏的基础上,我们增加一个判断语句,就会发现问题所在。

/*******  c文件   *******/
#define  fun printf("hello"); printf("world")
int main()
{
	int a=0;
	if (a == 0)
		fun;
	else
		...
	return 0;
}

/*******  预处理之后   *******/
int main()
{
	int a=0;
	if (a == 0)
		printf("hello"); printf("world");
	else
		...
	return 0;
}

(3)通过上面的代码,我们明显的发现了。如果是在if语句中,执行这个宏,会发现第二个语句不会包含在if语句中。这样就会导致,因为 if 分支后有两个语句,导致 else 分支没有对应的 if,编译失败
(4)这个时候可能就会有人说了,那我没有else语句呢?毫无疑问,可以编译通过,但是那样的话,printf(“world”);无论如何都会执行。
(5)上述问题无疑会给程序带来异常,那么do-while(0)的用途就出来了。
<1>处理了因为if语句所带来的问题。
<2>让程序更加美观。因为在每一条语句背后,我们都习惯性的加上“;”,但是在没有加do-while(0)的宏里面,最后一条语句不能加上“;”。这样容易导致阅读障碍。

/*******  c文件   *******/
#define  fun do{                  \
				printf("hello");  \
				printf("world");  \
			   }while(0)
int main()
{
	int a=0;
	if (a == 0)
		fun;
	else
		...
	return 0;
}

/*******  预处理之后   *******/
int main()
{
	int a=0;
	if (a == 0)
		do{printf("hello");printf("world");}while(0);
	else
		...
	return 0;
}

do-while(0)对于程序释放的优缺点

优点

(1)我们在Linux内核中,常常能够看到goto语句,用于进行一些程序的收尾工作。(比如卸载驱动,销毁设备号,注销GPIO)
(2)但是因为goto不符合软件工程的结构化,而且有可能使得代码难懂,而且很容易造成bug,被一些人戏称为,C语言禁术。

/*******  使用goto  *******/
void test_func(void)
{
    //申请资源 。。。
 
    if (!condition1) {
        goto exit_entry;
    }
 
    //执行一些逻辑
 
    if (!condition2) {
        goto exit_entry;
    }
 
    //执行一些逻辑
 
    if (!condition3) {
        goto exit_entry;
    }
 
    //执行一些逻辑
 
exit_entry:
    //释放资源 。。。
 
}
/*******  使用do-while(0)  *******/
void test_func(void)
{
    //申请资源 。。。
 
    do {
        if (!condition1) {
            break;
        }
 
        //执行一些逻辑
 
        if (!condition2) {
            break;
        }
 
        //执行一些逻辑
 
        if (!condition3) {
            break;
        }
 
        //执行一些逻辑
    } while(0);
 
exit_entry:
    //释放资源 。。。
 
}

缺点

(1)既然do-while(0)比goto好,那为什么大佬们依旧喜欢使用goto呢?
(2)因为在Linux驱动开发过程中,我们需要申请很多东西,一旦其中一个东西申请失败。就需要将前面申请的都释放掉,然后返回错误。
(3)可能还是有人没有明白。我现在举个例子,一个驱动程序,需要先完成A任务,再完成B任务,最后完成C任务。然后任务结束,就先执行c任务,然后执行b任务,最后执行a任务。大写字母的任务表示创建,小写字母的任务表示释放。他们执行顺序刚好相反。

// 创建
void create()
{
	A;
	B;
	C;
}
//销毁
void destroy()
{
	a;
	b;
	c;
}

(4)以上是按照一切顺利执行来编写程序的。但是,如果我A任务,B任务或者C任务有一个执行失败了。那怎么办呢?
(5)因为我们知道,如果A任务执行失败,只需要进行a任务。而B任务执行失败,就需要进行执行b和a了。如果使用do-while(0)语句,显然就很麻烦。而使用goto就会方便很多。

// 创建
void create()
{
	A;
	if(A创建失败)
		goto A_err;
	B;
	if(B创建失败)
		goto B_err;
	C;
	if(A创建失败)
		goto C_err;
C_err:
	c;
B_err:
	b;
A_err:
	a;
}

结论

因此,我们可以得出,如果一个函数最终的出口是固定的,而且有多个if判断语句执行的情况,使用do-while(0)更好。而如果函数出口不固定,按照顺序执行,那么goto就会更优秀。


标签:语句,do,goto,int,while,printf
From: https://blog.51cto.com/zyxfighting/6907980

相关文章

  • sudo相关权限
    使用sudo命令可以模拟其他用户执行其权限。这样你可以在不知道目标用户密码的情况下,以该用户的身份执行特定的命令或操作。下面是使用sudo模拟其他用户执行的方法:sudo-u目标用户命令在上述命令中,你需要将目标用户替换为你要模拟执行的实际用户名,而命令则是你要执行的特定命......
  • Alpine Linux使用入门(Docker视角)
    前言我们在了解AlpineLinux时,多数都应该是从docker系统镜像了解的这个操作系统,今天我们就简单说一下AlpineLinux的基础使用AlpineLinux是一种基于musl和BusyBox的Linux发行版,专为安全性、简单性和资源效率而设计。体积非常小巧,适合用来做Docker镜像。如果你有Centos或者Ubun......
  • mysql两表关联查询语句
    MySQL两表关联查询语句实现步骤引言在MySQL数据库中,两表关联查询是一种非常常见的查询操作。它允许我们通过在两个或多个表之间建立关联来获取更全面和有用的数据。本文将为刚入行的小白开发者介绍如何实现MySQL两表关联查询语句。步骤下面是实现MySQL两表关联查询语句的......
  • mysql跨表查询语句
    MySQL跨表查询语句在数据库查询中,跨表查询(也称为联合查询)是一种常见的操作,用于在多个表之间进行数据的关联和获取。MySQL提供了多种方法来实现跨表查询,本文将介绍一些常用的跨表查询语句及其使用示例。表的创建在进行跨表查询之前,我们需要先创建一些示例表格。假设我们有两个表......
  • Visual Studio 调试技巧[Command Window & Immediate Window ](Tips)
    VisualStudio调试技巧[CommandWindow&ImmediateWindow](Tips)1.immediatewindow定义的一些alias(//z2012-3-1314:04:44PMIS2120alias?Debug.Printalias??Debug.QuickWatchaliasAddProjFile.AddNewProjectaliasaliasTools.Al......
  • 使用DolphinDB TopN 函数探索高效的Alpha因子
    DolphinDB已经有非常多的窗口计算函数,例如m系列的滑动窗口计算,cum系列累计窗口计算,tm系列的的时间窗口滑动计算。但是所有这类函数都是对窗口内的所有记录进行指标计算,难免包含很多噪音。DolphinDB的金融领域用户反馈,通过交易量信息等对窗口内的记录进行过滤,得到的计算指标具......
  • python windows 开发环境搭建
    PythonWindows开发环境搭建作为一名经验丰富的开发者,我很乐意指导你如何搭建PythonWindows开发环境。本文将提供一个详细的步骤表格,并为每个步骤提供相应的代码和注释。让我们开始吧!步骤一:安装Python步骤描述1下载Python安装程序并运行。2选择“AddPythonto......
  • python while openfile
    Python中的while循环和文件操作在Python编程语言中,while循环是一种常见的控制结构,用于重复执行一段代码,直到满足某个条件为止。与之相对的是for循环,它用于遍历一个可迭代对象。本文将介绍while循环的基本语法和用法,并结合文件操作的实例进行演示。while循环的基本语法while循环......
  • iTOP-RK3568开发板Windows 安装 RKTool 驱动
    在烧写镜像之前首先需要安装RKTool驱动。RKTool驱动在网盘资料“iTOP-3568开发板\01_【iTOP-RK3568开发板】基础资料\02_iTOP-RK3568开发板烧写工具及驱动”路径下。驱动如下图所示:解压缩后,进入文件夹,如下图所示:点击“DriverInstall.exe”,如下图所示:如果出现提示,选择安装,如下......
  • How do I disable maven build when using Maven 2.0 integration for eclipse
    http://stackoverflow.com/questions/2865803/how-do-i-disable-maven-build-when-using-maven-2-0-integration-for-eclipseHowdoIstopthe"Maven2.0integration"pluginfromrunningmavenbuild,whilekeeping"buildautomatically"checked......