C++中错用宏定义造成的二义性

When writing code, the macro (#define) command is often used. Recently, I encountered two instances where macros were misused, so I’ll analyze them here.

Forgetting that macro parameters are simply replaced

The code is as follows:

1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;
// This macro is actually written incorrectly, as discussed later.
#define MAX(a,b) a>=b?a:b
int main(void){
int a,b;
cin>>a>>b;
cout<<MAX(a,b)<<endl;
return 0;
}

The above code implements a simple program to determine the larger of two numbers, and there is no issue here. However, problems arise when the parameters of MAX have side effects:

1
cout<<MAX(a--,b)<<endl;

When the parameter of MAX is MAX(a–,b), if the input data is a>b, then an error occurs:

After running, although the MAX value is 11, after executing cout<<MAX(a--,b)<<endl;, the value of a changes to 10.

Since define is just simple macro replacement, when the parameter of MAX has side effects, it becomes:

1
2
3
4
5
6
7
#define MAX(a,b) a>=b?a:b
// If parameter a has side effects, then cout<<MAX(a--,b)<<endl; is equivalent to:
if(a-->b){
cout<<a--<<endl;
}else{
cout<<b<<endl;
}

This means that if the input data is a>b, then a-- will be executed twice.

After rewriting the MAX macro into an equivalent if statement, the running result is as follows:

It matches the result of executing the MAX macro.

Ambiguity caused by a lack of parentheses in the macro

In the previous code, #define MAX(a,b) a>=b?a:b is wrong for the following reasons. In this case, if there are other expressions in the calling statement, it can also cause ambiguity! Consider the following code:

1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;
#define MAX(a,b) a>b?a:b
int main(void){
int a,b;
cin>>a>>b;
int max=MAX(a,b)*2;
cout<<max<<endl;
return 0;
}

Here, int max=MAX(a,b)*2; we expect to multiply the larger value between a and b by 2 and assign it to the variable max. However, as mentioned earlier, macros are just simple replacements, so the actual meaning of the above code is:

1
2
3
#define MAX(a,b) a>=b?a:b
// Then int max=MAX(a,b)*2; is equivalent to:
int max=a>=b?a:b*2;

The running result is as follows:

When a>=b, 2 will not be executed because the compiler treats b2 as an expression of the ternary operator.

Therefore, the safest and most correct way to write macro commands is:

  1. The macro command must include parentheses to ensure that the macro command acts as an independent expression.
  2. The macro parameters must also include parentheses to ensure the correct usage of each parameter (ensuring that side effects do not affect other parameters).
1
#define MAX(a,b) ((a)>=(b)?(a):(b))

Note: Always remember that a macro is just a simple and crude replacement, which may cause ambiguity!

The article is finished. If you have any questions, please comment and communicate.

Scan the QR code on WeChat and follow me.

Title:C++中错用宏定义造成的二义性
Author:LIPENGZHA
Publish Date:2016/03/14 19:07
World Count:1.7k Words
Link:https://en.imzlp.com/posts/38656/
License: CC BY-NC-SA 4.0
Reprinting of the full article is prohibited.
Your donation will encourage me to keep creating!