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
相关产品推荐
相关产品推荐

