结论:base填0则自动识别前缀(“0x”为十六进制、“0”开头为八进制,否则十进制),填2/8/10/16则强制按对应进制解析;填非标准值如3或36行为未定义,且C++17前不支持“0b”前缀。

std::stoul 的 base 参数到底怎么填
直接说结论:std::stoul 支持二进制、八进制、十进制、十六进制,靠第三个参数 base 控制。填 0 是自动推断(按前缀 "0x"/"0X" 判十六进制,"0" 开头判八进制,否则十进制),填具体数字就强制按该进制解析。
常见错误是传了非 0/2/8/10/16 的值——比如填 3 或 36,std::stoul 不报错但行为未定义(实际多数实现会静默截断或抛 std::invalid_argument)。
-
base = 0:依赖字符串前缀,"0b101"不被识别(C++17 起仍不支持"0b"前缀) -
base = 2:只接受'0'和'1',多一个'2'就抛std::invalid_argument -
base = 16:大小写不敏感,"FF"和"ff"都行,但"G"会立刻失败
处理二进制字符串时为什么总出错
因为标准库直到 C++17 都不识别 "0b" 或 "0B" 前缀。传 "0b1010" 给 std::stoul(s, nullptr, 0),它会当成十进制解析,卡在第一个 'b' 上直接抛异常。
正确做法只有两个:
立即学习“C++免费学习笔记(深入)”;
- 手动去掉前缀再调用:
std::stoul("1010", nullptr, 2) - 用
std::stoi或std::stoul前先做字符串预处理,例如:s.substr(0, 2) == "0b" ? std::stoul(s.substr(2), nullptr, 2) : std::stoul(s, nullptr, 0)
别指望编译器或标准库自动帮你识别 "0b" ——这不是 bug,是标准没规定。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
溢出时抛什么异常、怎么捕获
std::stoul 溢出时抛 std::out_of_range,不是 std::overflow_error,也不是 std::runtime_error。这点容易写错 catch 块。
典型场景:字符串是 "4294967296"(即 2³²),在 32 位 unsigned long 平台上必然溢出。
- 必须显式
catch (const std::out_of_range&),否则异常会向上逃逸 -
std::stoul不会返回 0 或最大值来“静默处理”,它严格遵循标准:无效输入抛std::invalid_argument,溢出抛std::out_of_range - 如果不想用异常,改用
std::strtoul(C 风格),它通过endptr和返回值配合判断,但要自己处理errno
不同平台下 unsigned long 大小影响结果
std::stoul 返回的是 unsigned long,而它的位宽在不同平台不同:Windows x64 是 32 位,Linux x64 通常是 64 位。这意味着同一串字符串,在 Windows 上可能溢出,在 Linux 上却能成功解析。
比如 "18446744073709551615"(2⁶⁴−1):
- 在 LP64 系统(Linux/macOS):
unsigned long是 64 位 → 成功 - 在 LLP64 系统(Windows):
unsigned long是 32 位 → 抛std::out_of_range
如果需要跨平台稳定行为,别用 std::stoul,改用 std::stoull(返回 unsigned long long,至少 64 位)或者 std::from_chars(C++17,无异常、无 locale 依赖、明确指定类型)。

















