sscanf或atoi将string转换为整数有什么区别?
gcc 4.4.4 c89
将string转换为整数值更好。
我已经尝试了2种不同的方法atoi和sscanf。 两者都按预期工作。
char digits[3] = "34"; int device_num = 0; if(sscanf(digits, "%d", &device_num) == EOF) { fprintf(stderr, "WARNING: Incorrect value for device\n"); return FALSE; }
或使用atoi
device_num = atoi(digits);
我以为sscanf会更好,因为你可以检查错误。 但是,atoi没有做任何检查。
你有3个select:
-
atoi
如果您在性能关键的代码中使用它,这可能是最快的,但它不会报告错误。 如果string不是以整数开始,则返回0.如果string在整数后面包含垃圾,它将转换初始部分,忽略其余部分。 如果这个数字太大而不能适应int
,那么这个行为是不确定的。
-
sscanf
有一些错误报告,而且对于什么types的存储( char/short/int/long/long long/size_t/ptrdiff_t/intmax_t
符号/无符号版本)有很大的灵活性。
返回值是成功的转换次数,所以如果string不是以整数开头的话,扫描"%d"
将返回0。 您可以使用"%d%n"
来存储在另一个variables中读取的整数之后的第一个字符的索引,从而检查整个string是否被转换或者之后是否有垃圾。 但是,像atoi
一样,整数溢出的行为是未指定的。
-
strtol
和家庭
强大的错误报告,只要您在打电话之前将errno
为0。 返回值在溢出时指定, errno
将被设置。 您可以select从2到36的任意数字基数,或者指定0作为基数,以自动解释前导0x
和0
分别为hex和八进制。 要转换的types的选项是long/long long/intmax_t
有符号/无符号版本。
如果你需要一个较小的types,你总是可以把结果存储在一个临时的long
或者unsigned long
variables中,然后检查溢出。
由于这些函数需要一个指向指针参数的指针,因此您还可以获得一个指向转换后的整数后的第一个字符的指针,因此您可以判断整个string是整数还是需要parsingstring中的后续数据。
就个人而言,我会为大多数目的推荐strtol
家族。 如果你正在做一些快速而又肮脏的事情,atoi可能会满足你的需求。
顺便说一句,有时我觉得我需要parsing数字,领先的空白符号等不应该被接受。 在这种情况下,你可以很容易地打开自己的循环,例如,
for (x=0; (unsigned)*s-'0'<10; s++) x=10*x+(*s-'0');
或者你可以使用(为了鲁棒性):
if (isdigit(*s)) x=strtol(s, &s, 10); else /* error */
*scanf()
函数族返回转换值的数量。 所以你应该检查以确保sscanf()
在你的情况下返回1。 EOF
返回“input失败”,这意味着ssacnf()
永远不会返回EOF
。
对于sscanf()
,函数必须parsing格式string,然后解码整数。 atoi()
没有那个开销。 两者都遭遇到超出范围的值导致未定义行为的问题。
您应该使用strtol()
或strtoul()
函数,它们提供更好的错误检测和检查。 他们也让你知道,如果整个string被消耗。
如果你想要一个int
,你总是可以使用strtol()
,然后检查返回值是否在INT_MIN
和INT_MAX
之间。
对@R ..我认为这是不够的,以检查errno
在strtol
调用错误检测。
long strtol (const char *String, char **EndPointer, int Base)
您还需要检查EndPointer
是否有错误。
结合R ..和PickBoy答案为简洁起见
long strtol (const char *String, char **EndPointer, int Base) // examples strtol(s, NULL, 10); strtol(s, &s, 10);
当不需要关心无效stringinput或范围问题时,使用最简单的方法: atoi()
否则,具有最佳误差/范围检测的方法既不是atoi()
也不是sscanf()
。 这个好的答案都准备好了详细信息,缺less使用atoi()
错误检查和使用sscanf()
一些错误检查。
strtol()
是将string转换为int
的最严格的函数。 但这只是一个开始。 下面是详细的例子,以显示正确的用法,所以这个答案的理由后, 接受 。
// Over-simplified use int strtoi(const char *nptr) { int i = (int) strtol(nptr, (char **)NULL, 10); return i; }
这就像atoi()
,忽略了使用strtol()
的错误检测function。
要充分使用strtol()
,需要考虑各种function:
-
检测不转换 :例如:
"xyz"
或""
或"--0"
? 在这些情况下,endptr
将匹配nptr
。char *endptr; int i = (int)strtol(nptr, &endptr, 10); if (nptr == endptr) return FAIL_NO_CONVERT;
-
如果整个string转换或只是领导部分:是
"123xyz"
好吗?char *endptr; int i = (int)strtol(nptr, &endptr, 10); if (*endptr != '\0') return FAIL_EXTRA_JUNK;
-
检测值是否如此之大,其结果不能像
"999999999999999999999999999999"
那样long
。errno = 0; long L = strtol(nptr, &endptr, 10); if (errno == ERANGE) return FAIL_OVERFLOW;
-
检测值是否超出
int
的范围,但不会long
。 如果int
和long
具有相同的范围,则不需要此testing。long L = strtol(nptr, &endptr, 10); if (L < INT_MIN || L > INT_MAX) return FAIL_INT_OVERFLOW;
-
有些实现超出了C标准,并且由于其他原因而设置了
errno
,例如在没有执行转换的情况下从errno到EINVAL,或者EINVAL
Base参数的值无效。 。 testing这些errno
值的最佳时间是与实现相关的。
把这一切放在一起:(调整你的需要)
#include <errno.h> #include <stdlib.h> int strtoi(const char *nptr, int *error_code) { char *endptr; errno = 0; long i = strtol(nptr, &endptr, 10); #if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX if (errno == ERANGE || i > INT_MAX || i < INT_MIN) { errno = ERANGE; i = i > 0 : INT_MAX : INT_MIN; *error_code = FAIL_INT_OVERFLOW; } #else if (errno == ERANGE) { *error_code = FAIL_OVERFLOW; } #endif else if (endptr == nptr) { *error_code = FAIL_NO_CONVERT; } else if (*endptr != '\0') { *error_code = FAIL_EXTRA_JUNK; } else if (errno) { *error_code = FAIL_IMPLEMENTATION_REASON; } return (int) i; }
注意:提到的所有function都允许前导空格,一个可选的前导符号字符,并受到语言环境变化的影响。 更多限制的转换需要额外的代码。
注:非OP标题变更偏重。 这个答案更适用于原始标题“convert string to integer sscanf or atoi”
如果用户input34abc,并将它们传递给atoi,它将返回34.如果要validationinput的值,则必须迭代地在input的string上使用isdigit