17

according documentation:

成功すると、関数は変換された整数をlongint値として返します。有効な変換を実行できなかった場合は、ゼロ値が返されます。正しい値が表現可能な値の範囲外である場合、LONG_MAXまたはLONG​​_MINが返され、グローバル変数errnoがERANGEに設定されます。

関数が失敗したのか、それとも文字列を数字で変換しただけなのstrtol(str, (char**)NULL, 10);str"0\0"知る方法を検討してください。"0"

4

5 に答える 5

19

エラーチェックが必要な場合は、実際のポインタアドレスを渡す必要があります。これにより、次の値から発生する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
于 2012-07-01T05:25:37.463 に答える
5

受け入れられた答えは実際には失敗をチェックする正しい方法ではないので。

文字列は0l、LONG_MAX、またはLONG​​_MINの有効な表現である可能性があるため、strtolの戻り値を調べてエラーをチェックしないでください。代わりに、tailptrが数字の後に期待するものを指しているかどうかを確認してください(たとえば、文字列が数字の後に終わる必要がある場合は「\ 0」)。また、オーバーフローが発生した場合に備えて、呼び出しの前にerrnoをクリアし、後で確認する必要があります。

于 2018-06-28T12:04:32.690 に答える
4

私見、私sscanf()atoi()またはを好みstrtol()ます。主な理由は、使用しない限り、一部のプラットフォーム(Windowsなど)でエラーステータスを確実にチェックできないことです成功た場合と失敗した場合に返されます)。sscanf()10

于 2012-07-01T05:24:52.470 に答える
2

私はすべてのエッジケースをチェックしたと思います。私が見逃したエッジケースを誰かが考えた場合は、コメントで知らせてください。この投稿を更新します。エラーメッセージをシンプルにしようとしました。この決定に同意できない場合は、必要に応じて自由に変更してください。

// 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()番号が始まるところにも戻ってきたいです。終了ポインタから繰り返すことでこれを理解できますが、時間がかかる場合があります。

于 2021-03-26T21:32:13.370 に答える
1

をチェックするerrnoか、2番目の引数にNULL以外の値を渡して、結果の値を次strのように比較できます。

char * endptr;
long result = strtol(str, &endptr, 10);
if (endptr > str)
{
    // Use result...
}
于 2012-07-01T05:24:28.440 に答える