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 longvariables中,然后检查溢出。
由于这些函数需要一个指向指针参数的指针,因此您还可以获得一个指向转换后的整数后的第一个字符的指针,因此您可以判断整个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,或者EINVALBase参数的值无效。 。 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