[英]Check if a string representing float/unsigned int is too big
我有一个文件,其中包含表示float
和uint64_t
值的字符串。
我确切地知道哪个字符串包含float
值,哪个字符串包含uint64_t
值——这不是我面临的问题。
以下是我如何将它们转换为各自的数据类型:
char* t, v;
uint64_t cn;
cn = strtoull(t, &v, 10);
char* tt, vv;
float cn2;
cn2 = strtof(tt, vv);
但是问题出现在我想捕捉的以下边缘情况:
假设uint64_t
的字符串是"99999999999999999999999999999999999999999999999999"
这不能在 8 个字节内表示,因此会导致溢出,导致cn = 18446744073709551615
。
float cn2
有同样的问题。
怎样才能捕捉到这种行为?
strtoull
指示该值超出范围。 考虑这段代码:
#include <errno.h>
…
errno = 0; // Set error code to zero before call.
unsigned long long x = strtoull(t, &v, 10);
if (errno == ERANGE)
{
// Handle out-of-range error.
}
如果t
中的数字太大,这将达到错误情况。
请注意,如果t
包含一个减号(但幅度不是太大), strtoull
将返回一个在unsigned long long
类型中“取反”的值(即环绕ULLONG_MAX
+1 的值),即使是负数值超出类型范围; 不会提供错误指示。 所以,如果你想检测所有超出范围的情况,你必须检查t
是否有一个非零返回值的减号(可能在前导空格之后)。
根据 C 2018 7.22.1.3 10, strtof
提供了足够的信息来区分案例:
HUGE_VALF
并将errno
设置为ERANGE
。-HUGE_VALF
并将errno
设置为ERANGE
。errno
设置为ERANGE
。根据这个strtoull
参考,当发生溢出时,它将返回ULLONG_MAX
并且errno
设置为ERANGE
。
因此,您应该在调用之前将errno
为零,之后可以检查ULLONG_MAX
和errno == ERANGE
以查看是否发生溢出。
如果值小于 0 需要检测
strtoull("-1", ..., ...)
“换行”并返回ULLONG_MAX
。
strto(u)ll()
至少转换为 64 位整数。 为unsigned long long
可能超过 64 位的未来增长做计划。
例子:
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
uint64_t convert_str_uint64(const char *s, char **endptr, int base) {
errno = 0;
long long ival = strtoll(s, endptr, base);
// Look for negative numbers
if (ival < 0) {
errno = ERANGE;
return 0;
}
// We are done for many positive numbers
if (*endptr > s && ival <= INT64_MAX && errno == 0) {
return (uint64_t) ival;
}
// Input may still be a valid value more than INT64_MAX.
errno = 0;
unsigned long long uval = strtoull(s, endptr, base);
#if ULLONG_MAX > UINT64_MAX
if (uval > UINT64_MAX) {
uval = UINT64_MAX;
errno = ERANGE;
}
#endif
return (uint64_t) uval;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.