成功すると、関数は変換された整数をlongint値として返します。有効な変換を実行できなかった場合は、ゼロ値が返されます。正しい値が表現可能な値の範囲外である場合、LONG_MAXまたはLONG_MINが返され、グローバル変数errnoがERANGEに設定されます。
関数が失敗したのか、それとも文字列を数字で変換しただけなのstrtol(str, (char**)NULL, 10);
かstr
を "0\0"
知る方法を検討してください。"0"
成功すると、関数は変換された整数をlongint値として返します。有効な変換を実行できなかった場合は、ゼロ値が返されます。正しい値が表現可能な値の範囲外である場合、LONG_MAXまたはLONG_MINが返され、グローバル変数errnoがERANGEに設定されます。
関数が失敗したのか、それとも文字列を数字で変換しただけなのstrtol(str, (char**)NULL, 10);
かstr
を "0\0"
知る方法を検討してください。"0"
エラーチェックが必要な場合は、実際のポインタアドレスを渡す必要があります。これにより、次の値から発生する0の値"0"
と、次の値から発生する0の値を区別でき"pqr"
ます。
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
受け入れられた答えは実際には失敗をチェックする正しい方法ではないので。
文字列は0l、LONG_MAX、またはLONG_MINの有効な表現である可能性があるため、strtolの戻り値を調べてエラーをチェックしないでください。代わりに、tailptrが数字の後に期待するものを指しているかどうかを確認してください(たとえば、文字列が数字の後に終わる必要がある場合は「\ 0」)。また、オーバーフローが発生した場合に備えて、呼び出しの前にerrnoをクリアし、後で確認する必要があります。
私見、私sscanf()
はatoi()
またはを好みstrtol()
ます。主な理由は、使用しない限り、一部のプラットフォーム(Windowsなど)でエラーステータスを確実にチェックできないことです(成功した場合と失敗した場合に返されます)。sscanf()
1
0
私はすべてのエッジケースをチェックしたと思います。私が見逃したエッジケースを誰かが考えた場合は、コメントで知らせてください。この投稿を更新します。エラーメッセージをシンプルにしようとしました。この決定に同意できない場合は、必要に応じて自由に変更してください。
// 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");
}
このサイズの構造体を値で返すことに反対する場合は、追加の引数として構造体へのポインターを渡します。構造体ポインターがの場合を処理することを忘れないでくださいNULL
。私の目標は、このコードを理解しやすくすることでした。おそらく、チェックを組み合わせて、戻り値の設定を一元化する必要があります。
strtol()
番号が始まるところにも戻ってきたいです。終了ポインタから繰り返すことでこれを理解できますが、時間がかかる場合があります。
をチェックするerrno
か、2番目の引数にNULL以外の値を渡して、結果の値を次str
のように比較できます。
char * endptr;
long result = strtol(str, &endptr, 10);
if (endptr > str)
{
// Use result...
}