What exactly is the do-while(0) statement for?

foreword

I saw a person asking in a group, what is the use of the do-while(0) statement? The final result of the do-while(0) program should not be that the program only runs once, so what is the difference between writing and not writing?

Advantages of do-while(0) in complex macro definitions

Why do you need complex macros

(1) Before explaining the advantages of do-while(0) in the definition of complex macros, let me first introduce the benefits of complex macros.
(2) When we see that a macro definition is very complicated, we naturally think, why not make it a function? It is not as convenient to directly define a function to get such bells and whistles in the macro definition.
(3) After I asked the exchange group with such a question, a big guy immediately gave a reply.
<1>He said that when he was working on an 8-bit single-chip microcomputer, he didn't dare to call the functions in depth, and many of them were written macro functions. Because resources are limited.
<2> The big brother introduced that which one of his single-chip microcomputers, the hardware stack, seems to be 7 layers, and two layers are reserved for interrupts. Some C standard functions use two layers of stacks, and the ones written by myself are limited to about 3-4 layers. Because the stack is limited, I'm afraid becauseIf the in-depth call of the function is too frequent or the number of recursive layers is too deep, the stack space may be insufficient and a stack overflow may occur. When the stack space is not enough to accommodate the new stack frame, the program will crash or terminate abnormally.
<3> So they wrote code like this back then

insert image description here

Advantages

(1) When we are writing business logic, we may need to define a more complex macro. as follows

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

(2) On the basis of this macro, if we add a judgment statement, we will find the problem.

/*******  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) Through the above code, we obviously found out. If it is in the if statement, execute this macro, and you will find that the second statement will not be included in the if statement. This will cause, because there are two statements after the if branch, the else branch does not have a corresponding if, and the compilation fails .
(4) Someone may say it at this time, so what if I don't have an else statement? There is no doubt that it can be compiled, but in that case, printf("world"); will be executed anyway.
(5) The above problems will undoubtedly bring exceptions to the program, so the purpose of do-while(0) comes out.
<1>Solved the problem caused by the if statement.
<2>Make the program more beautiful. Because we habitually add ";" behind each statement, but in the macro without do-while(0), the last statement cannot add ";". This can easily lead to dyslexia.

/*******  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;
}

Advantages and disadvantages of do-while(0) for program release

advantage

(1) In the Linux kernel, we can often see goto statements, which are used to finish some programs. (such as uninstalling the driver, destroying the device number, and canceling GPIO)
(2) But because goto does not conform to the structure of software engineering, and it may make the code difficult to understand, and it is easy to cause bugs, it is jokingly called by some people, C language forbidden technique .

/*******  使用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:
    //释放资源 。。。
 
}

shortcoming

(1) Since do-while(0) is better than goto, why do big guys still like to use goto?
(2) Because in the Linux driver development process, we need to apply for many things, once one of the things fails to apply. It is necessary to release all the previous applications, and then return an error.
(3) Some people may still not understand. Let me give you an example now. A driver needs to complete task A first, then task B, and finally task C. Then the task ends, first executes the c task, then executes the b task, and finally executes the a task. Tasks in uppercase letters indicate creation, and tasks in lowercase letters indicate release. They execute in the exact opposite order.

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

(4) The above is to write the program according to the smooth execution of everything. However, if one of my A task, B task or C task fails to execute. then what should we do?
(5) Because we know that if task A fails, only task a needs to be performed. If task B fails to execute, b and a need to be executed. If you use the do-while(0) statement, it is obviously very troublesome. And using goto will be much more convenient.

// 创建
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;
}

in conclusion

Therefore, we can conclude that if the final exit of a function is fixed, and there are multiple if judgment statements to be executed, it is better to use do-while(0). And if the function exit is not fixed and executed in order, then goto will be better.

Guess you like

Origin blog.csdn.net/qq_63922192/article/details/131360041