In verification, when using the C language construct case, macros are often utilized. Sometimes, you may see a #define that wraps a piece of code with do…while(0), even though it only executes once. Why use do…while(0 and what is its purpose?
The C language uses macros to implement a function: defining two integer variables x and y. If x<y, it prints the string “x<y“, and simultaneously swaps the values of x and y. The macro definition to implement the swap function is as follows:
#define SWAP(x, y) \
printf(“x<y\n”);\
int tmp;\
tmp = x;\
x= y;\
y= tmp;
In the main function, the SWAP macro is called as follows:
if (x < y)
SWAP(x, y);
We will find that in this case, regardless of the relationship between x and y, the swap will always execute because the macro expands to the following code:
if (x < y)
printf(“x<y\n”);
int tmp;
tmp = x;
x= y;\
y= tmp;
This does not align with the functionality we expect. So how do we solve this problem? We can wrap the code in the macro definition using {}, as shown below:
#define SWAP(x, y) { \
printf(“x<y\n”);\
int tmp;\
tmp = x;\
x= y;\
y= tmp;\
}
The expanded macro code is as follows:
if (x < y) {
printf(“x<y\n”);
int tmp;
tmp = x;
x= y;
y= tmp;
};
Is this modification foolproof? Let’s look at another example. In the previous main function call to the SWAP macro code snippet, there is only the if branch. If x is greater than or equal to y, we need to print “x>=y” in the else branch. The main function call code snippet is as follows:
if (x < y)
SWAP(x, y);
else
printf(“x>=y\n”);
At this point, a compilation error will occur, with a message similar to:
error: ‘else’ without a previous ‘if’
else
^
The error is due to an extra semicolon before the else. To resolve this compilation error, it is acceptable not to add a semicolon at the end of the SWAP macro call, but this does not conform to the C language coding style. Of course, wrapping the call statement SWAP(x,y) with {} can also solve this issue. In this case, if we use do…while(0), the constructed macro definition will not be affected by semicolons or braces, ensuring it aligns with our expected functionality. The macro definition is as follows:
#define SWAP(x, y) \
do {\
printf(“x<y\n”);\
int tmp;\
tmp = x;\
x= y;\
y= tmp;\
} while (0)
The do…while(0) in the macro definition has other functions as well, such as avoiding compilation Warnings caused by empty macros. To avoid compilation warnings from empty macros, we can use do…while(0) to define empty macros, which can be seen in kernel code or some open-source code. For example, in kernel code, empty macros are used:
