C++中max函数/宏返回值异常 行为类似min的问题排查
问题背景
说明:本问题对应USACO的teleportation题目,变量名特殊为题目适配,并非开发实际传送门程序。
遇到的异常现象:使用内置max函数计算(2,8)的最大值时错误返回结果2,自行编写如下min/max宏定义后运行依然异常:
#define min(number_1, number_2) (number_1 < number_2 ? number_1 : number_2) #define max(number_1, number_2) (number_1 < number_2 ? number_2 : number_1)
完整可复现代码如下:
#include <iostream> #include <string> using namespace std; #define min(number_1, number_2) (number_1 < number_2 ? number_1 : number_2) #define max(number_1, number_2) (number_1 < number_2 ? number_2 : number_1) int main() { int start_position, end_position; int teleportation_start_position, teleportation_end_position; cin >> start_position >> end_position >> teleportation_start_position >> teleportation_end_position; cout << start_position << " " << end_position << " " << teleportation_start_position << " " << teleportation_end_position << "\n"; start_position = min(start_position, end_position); end_position = max(start_position, end_position); teleportation_start_position = min(teleportation_start_position, teleportation_end_position); teleportation_end_position = max(teleportation_start_position, teleportation_end_position); cout << start_position << " " << end_position << " " << teleportation_start_position << " " << teleportation_end_position << "\n"; }
使用测试输入:
3 10 8 2
得到实际输出:
3 10 8 2 3 10 2 2
预期传送门起止位置排序后应为2、8,实际输出为2、2,且删除自定义宏定义后问题仍然存在。
补充说明:
- 提问者为C++初学者,此前主要使用Python编程
- 代码中的不规范写法为竞赛编程场景的适配习惯
错误原因
这个问题和max函数、自定义宏都没有关系,是赋值顺序导致的逻辑错误:
你在对两个变量排序时,先修改了第一个变量的值,再用修改后的值计算第二个变量,导致原始值丢失。
以传送门变量的计算逻辑为例,代入输入初始值:teleportation_start_position = 8,teleportation_end_position = 2
- 执行第一行赋值:
teleportation_start_position = min(8, 2),计算得2,此时teleportation_start_position被覆盖为2,原来的8已经丢失 - 执行第二行赋值:
teleportation_end_position = max(teleportation_start_position, teleportation_end_position),此时传入max的两个参数是修改后的2和原始值2,计算结果自然是2,最终两个变量都为2。
之前处理start_position和end_position时没有出错,只是刚好输入的初始值3<10,第一行min计算后start_position还是3,没有被修改,属于巧合。如果输入start大于end的测试用例,这两个变量同样会出现计算错误。
修复方案
不要在计算完两个值的min、max之前覆盖原始变量,两种常用写法:
- 先用临时变量保存计算出的最小值、最大值,再统一赋值:
// 处理起点终点 int s_min = min(start_position, end_position); int s_max = max(start_position, end_position); start_position = s_min; end_position = s_max; // 处理传送门坐标 int t_min = min(teleportation_start_position, teleportation_end_position); int t_max = max(teleportation_start_position, teleportation_end_position); teleportation_start_position = t_min; teleportation_end_position = t_max;
- 直接判断大小,不符合顺序就交换两个变量:
if (start_position > end_position) { swap(start_position, end_position); } if (teleportation_start_position > teleportation_end_position) { swap(teleportation_start_position, teleportation_end_position); }
额外提示:自定义的min/max宏存在运算符优先级、参数重复求值的隐患,竞赛场景下如果要使用需要给每个参数和整体表达式都加括号,更稳妥的方式是直接使用C++标准库提供的std::min、std::max。
内容的提问来源于stack exchange,提问作者Codeman
相关产品推荐
相关产品推荐

