[英]How do I make sure that strtol() have returned successfully?
On success, the function returns the converted integral number as a long int value.
成功时,该函数将转换后的整数作为 long int 值返回。 If no valid conversion could be performed, a zero value is returned.
如果无法执行有效转换,则返回零值。 If the correct value is out of the range of representable values, LONG_MAX or LONG_MIN is returned, and the global variable errno is set to ERANGE.
如果正确值超出可表示值的范围,则返回 LONG_MAX 或 LONG_MIN,并将全局变量 errno 设置为 ERANGE。
Consider strtol(str, (char**)NULL, 10);
考虑
strtol(str, (char**)NULL, 10);
if str
is "0\\0"
how to know if the function failed or only has converted the string with "0"
number?如果
str
是"0\\0"
如何知道函数是否失败或只转换了带有"0"
数字的字符串?
You need to pass a real pointer address if you want error checking, so you can distinguish 0 values arising from "0"
and similar from 0 values arising from "pqr"
:如果你想进行错误检查,你需要传递一个真实的指针地址,这样你就可以区分由
"0"
产生的 0 值和由"pqr"
产生的 0 值类似:
char *endptr;
errno = 0;
long result = strtol(str, &endptr, 10);
if (endptr == str)
{
// nothing parsed from the string, handle errors or exit
}
if ((result == LONG_MAX || result == LONG_MIN) && errno == ERANGE)
{
// out of range, handle or exit
}
// all went fine, go on
Since the accepted answer is not actually a correct way to check for failure.由于接受的答案实际上并不是检查失败的正确方法。
You should not check for errors by examining the return value of strtol, because the string might be a valid representation of 0l, LONG_MAX, or LONG_MIN.您不应通过检查 strtol 的返回值来检查错误,因为该字符串可能是 0l、LONG_MAX 或 LONG_MIN 的有效表示。 Instead, check whether tailptr points to what you expect after the number (eg '\\0' if the string should end after the number).
相反,检查 tailptr 是否指向您期望的数字后(例如,如果字符串应在数字后结束,则为 '\\0')。 You also need to clear errno before the call and check it afterward, in case there was overflow.
您还需要在调用之前清除 errno 并在调用之后检查它,以防出现溢出。
IMHO, I prefer sscanf()
to atoi()
or strtol()
.恕我直言,我更喜欢
sscanf()
到atoi()
或strtol()
。 The main reason is that you cannot reliably check for error status on some platforms (ie Windows) unless you use sscanf()
(which returns 1
if you succeed, and 0
if you fail).主要原因是您无法在某些平台(即 Windows)上可靠地检查错误状态,除非您使用
sscanf()
(如果成功则返回1
,如果失败则返回0
)。
I think I checked all the edge cases.我想我检查了所有的边缘情况。 If anyone thinks of an edge case that I missed please let me know in the comments and I will update this post.
如果有人想到我遗漏的边缘情况,请在评论中告诉我,我会更新这篇文章。 I tried to keep the error messages simple.
我试图使错误消息保持简单。 If you disagree with this decision please feel free to change them as you see fit.
如果您不同意此决定,请随时按照您认为合适的方式进行更改。
// Copyright (C) 2021 by cmwt
// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <errno.h> // errno, ERANGE
#include <limits.h> // LONG_MAX, LONG_MIN
#include <stdbool.h> // true, false
#include <stddef.h> // ptrdiff_t
#include <stdio.h> // printf()
#include <stdlib.h> // strtol()
struct ResultToLong {
const char *err_msg;
long answer;
ptrdiff_t num_read;
bool is_func_success;
};
struct ResultToLong stringToLong(const char* start, int base) {
struct ResultToLong result = {NULL, 0, 0, false};
int save_errno = 0;
char *end = NULL;
if (base < 0 || base > 36) {
result.err_msg = "Bad base: expect (0 <= base <= 36)";
return result;
}
if (start == NULL) {
result.err_msg = "Bad start: expect (start != NULL)";
return result;
}
if (*start == '\0') {
result.err_msg = "Bad start: start empty (const char* start == \"\";)";
return result;
}
errno = 0;
result.answer = strtol(start, &end, base);
save_errno = errno;
if (result.answer == 0 && *(start - 1) != '0') {
result.err_msg = "Bad start: not a number";
result.num_read = end - start;
return result;
}
if (result.answer == LONG_MIN && save_errno == ERANGE) {
result.err_msg = "Bad start: result < LONG_MIN";
result.num_read = end - start;
return result;
}
if (result.answer == LONG_MAX && save_errno == ERANGE) {
result.err_msg = "Bad start: result > LONG_MAX";
result.num_read = end - start;
return result;
}
if (*end != '\0') {
result.err_msg = "Warning: number in start is not '\\0' terminated";
result.num_read = end - start;
result.is_func_success = true;
return result;
}
result.err_msg = "Success";
result.num_read = end - start;
result.is_func_success = true;
return result;
}
int main() {
struct ResultToLong result;
const char* str;
printf("Starting...\n\n");
str= NULL;
result = stringToLong(str, 0);
printf("Response message: %s\n", result.err_msg);
printf("Input string: %s\n", "<NULL>");
printf("Number of chars processed: %ld\n", result.num_read);
printf("Result: %ld\n\n", result.answer);
str= "";
result = stringToLong(str, 0);
printf("Response message: %s\n", result.err_msg);
printf("Input string: '%s'\n", str);
printf("Number of chars processed: %ld\n", result.num_read);
printf("Result: %ld\n\n", result.answer);
str= "42";
result = stringToLong(str, -1);
printf("Response message: %s\n", result.err_msg);
printf("Input string: '%s'\n", str);
printf("Number of chars processed: %ld\n", result.num_read);
printf("Result: %ld\n\n", result.answer);
str= "42";
result = stringToLong(str, 0);
printf("Response message: %s\n", result.err_msg);
printf("Input string: '%s'\n", str);
printf("Number of chars processed: %ld\n", result.num_read);
printf("Result: %ld\n\n", result.answer);
str= "42 ";
result = stringToLong(str, 0);
printf("Response message: %s\n", result.err_msg);
printf("Input string: '%s'\n", str);
printf("Number of chars processed: %ld\n", result.num_read);
printf("Result: %ld\n\n", result.answer);
str= " 42";
result = stringToLong(str, 0);
printf("Response message: %s\n", result.err_msg);
printf("Input string: '%s'\n", str);
printf("Number of chars processed: %ld\n", result.num_read);
printf("Result: %ld\n\n", result.answer);
str= "0x42";
result = stringToLong(str, 0);
printf("Response message: %s\n", result.err_msg);
printf("Input string: '%s'\n", str);
printf("Number of chars processed: %ld\n", result.num_read);
printf("Result: %ld\n\n", result.answer);
str= "042";
result = stringToLong(str, 0);
printf("Response message: %s\n", result.err_msg);
printf("Input string: '%s'\n", str);
printf("Number of chars processed: %ld\n", result.num_read);
printf("Result: %ld\n\n", result.answer);
str= "+9999999999999999999";
result = stringToLong(str, 0);
printf("Response message: %s\n", result.err_msg);
printf("Input string: '%s'\n", str);
printf("Number of chars processed: %ld\n", result.num_read);
printf("Result: %ld\n\n", result.answer);
str= "-9999999999999999999";
result = stringToLong(str, 0);
printf("Response message: %s\n", result.err_msg);
printf("Input string: '%s'\n", str);
printf("Number of chars processed: %ld\n", result.num_read);
printf("Result: %ld\n\n", result.answer);
str= "?";
result = stringToLong(str, 0);
printf("Response message: %s\n", result.err_msg);
printf("Input string: '%s'\n", str);
printf("Number of chars processed: %ld\n", result.num_read);
printf("Result: %ld\n\n", result.answer);
printf("Done.\n");
}
If you object to returning a struct of this size by value then pass a pointer to the struct as an additional argument, just don't forget to handle the case where the struct pointer is NULL
.如果您反对按值返回此大小的结构,然后将指向该结构的指针作为附加参数传递,请不要忘记处理结构指针为
NULL
。 My goal was to make this code easy to understand.我的目标是使这段代码易于理解。 You probbaly want combine checks and centralize setting the the return values.
您可能希望结合检查并集中设置返回值。
I kinda wish strtol()
would also return where the number starts.我有点希望
strtol()
也能返回数字开始的地方。 You could figure this out by iterating back from the end pointer but it might be slow.您可以通过从结束指针返回来解决这个问题,但它可能会很慢。
You can either check the errno
or pass a non-NULL value for the second argument and compare its resulting value to str
, like:您可以检查
errno
或为第二个参数传递一个非 NULL 值并将其结果值与str
进行比较,例如:
char * endptr;
long result = strtol(str, &endptr, 10);
if (endptr > str)
{
// Use result...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.