You need to enable JavaScript to run this app. strtoull是否保证返回有效数值或设置errno?对应错误检查逻辑是否正确?
优惠活动
大模型
产品
解决方案
定价
更多

strtoull是否保证返回有效数值或设置errno?对应错误检查逻辑是否正确?

strtoull的正确校验逻辑

你写的这段代码完全不正确,仅靠检查errno根本覆盖不了所有无效输入场景,会漏掉大量边界情况。

strtoull的标准行为约定

C语言对strtoull的错误状态是拆分传递的,并非所有错误都会设置errno:

  • 只有解析出的数值超出unsigned long long的可表示范围时,才会设置errno为ERANGE,同时返回ULLONG_MAX作为返回值
  • 所有和输入格式相关的错误——比如根本没解析到有效数字、数字后面附带无效字符——完全不会修改errno,这类状态只会通过函数的第二个入参(也就是你代码里传成0的“解析终止位置指针”)传递给调用方。

原代码会漏检的无效输入场景

只检查errno的话,至少会把三类无效输入当成合法值处理:

  • 完全没有有效数字的字符串:比如空串、全空白字符的串、"abc123"这类开头就不是数字的串。这时候strtoull会返回0,errno保持你提前设置的0值,代码会误把这个无效输入当成合法的0值使用。
  • 带多余尾字符的数字串:比如"123abc"、"456 "(数字后面带空格)这类输入。strtoull会正常解析出123、456,errno为0,代码会误判整个字符串都是合规的纯数字输入。
  • 带负号的回绕无符号值:strtoull原生支持解析负号,比如传入"-1",它既不会报错也不会设置errno,会按照无符号整数规则把值回绕成ULLONG_MAX返回。如果业务场景不接受带负号的输入,这个值也会被误判为合法的大数值。

可靠的校验流程必须覆盖所有状态

完整的校验逻辑不能只盯着errno,需要把解析进度、范围错误、剩余字符全部检查到:

char *endptr = NULL;
errno = 0;
n = strtoull(s, &endptr, 10);

// 第一步:检查数值溢出的算术错误
if (errno == ERANGE) {
    perror(s);
    exit(1);
}
// 第二步:检查是否完全没解析到有效数字
if (endptr == s) {
    fprintf(stderr, "输入%s无有效数字可解析\n", s);
    exit(1);
}
// 第三步:检查数字后面是否附带未解析的无效字符(可根据业务需求决定是否强制校验)
if (*endptr != '\0') {
    fprintf(stderr, "输入%s包含非数字的无效字符\n", s);
    exit(1);
}
// 可选:如果业务不支持负号输入,额外校验数字前缀是否带'-'
// 全部校验通过后,n才是可安全使用的合法值

常见踩坑原因

很多人写这段代码时会犯和原代码一样的错:把第二个参数传成NULL,以为查errno就够了。本质是对strtoull的设计逻辑理解偏差——C标准从设计之初就把这类字符串转换函数的错误做了拆分:算术层面的溢出错误通过errno传递,格式层面的解析进度通过endptr指针传递,两者缺任意一个,都会漏检无效输入。


内容的提问来源于stack exchange,提问作者rwallace

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.03 13:06:08