C++17起可用std::gcd,需包含<numeric>并指定-std=c++17;参数为0时行为未定义;手写应取abs防负数,用迭代避免栈溢出,模板化支持long long等类型。

std::gcd 在 C++17 里直接用,但得开标准
如果你用的是 C++17 或更新(比如 GCC 7+、Clang 6+、MSVC 2017 Update 5+),std::gcd 已经是标准库函数,不用自己写。但它不在 <iostream> 里,得包含 <numeric>,而且编译时要明确指定标准:
-
g++ -std=c++17 main.cpp(不加-std默认可能是 C++14,std::gcd就报错:‘gcd’ is not a member of ‘std’) - 返回值类型是参数类型的公共类型(比如
int和long传进去,返回long) - 两个参数都为 0 时行为未定义——实际运行可能抛异常或返回 0,别这么调用
手写辗转相除法要注意负数和零
经典递归/迭代写法看似简单,但 C++ 里 % 是取余(remainder),不是数学上的模(modulo)。负数参与运算时结果符号依赖被除数,容易让 gcd(-8, 12) 算出负值或死循环:
- 安全做法是先取绝对值:
abs(a)和abs(b)再进算法 - 边界检查不能只写
b == 0,得处理a == 0 && b == 0的情况(按定义应返回 0,但很多实现会崩溃) - 迭代版比递归更稳,避免栈溢出(尤其大数场景)
int gcd(int a, int b) {
a = abs(a); b = abs(b);
while (b != 0) {
int r = a % b;
a = b;
b = r;
}
return a;
}
unsigned 类型下 % 更干净,但没法输负数
如果业务确定输入非负(比如数组长度、内存块大小),用 unsigned int 能省掉 abs,且 % 行为完全确定:
-
unsigned下a % b永远 ≥ 0,不会出现负余数干扰逻辑 - 但一旦传入负数,会触发静默整型提升成大正数(比如
-1变成4294967295),结果完全不可控 - 接口设计时建议显式用
int+abs,比靠文档“约定不传负数”更可靠
模板版本支持 long long 和自定义整型
标准 std::gcd 是函数模板,能推导 long long、int128_t(GCC 扩展)等;自己写的也要考虑泛化:
立即学习“C++免费学习笔记(深入)”;
- 别硬写
int,用typename T+static_assert(std::is_integral_v<T>) -
std::gcd对long long安全,但手写时若用int中间变量存余数,可能溢出(比如LLONG_MAX % 2还是大数,但塞进int就截断) - 如果项目禁用 STL 或需兼容旧编译器,推荐抄 libstdc++ 的实现:用
__gcd(GCC 内部函数,非标准但稳定)
int 和 long long 参数时,连 std::gcd 都可能隐式转换出错。










