Как проверить строку, которая является числом для> INT_MAX или - PullRequest
0 голосов
/ 26 марта 2020

Используется пользовательский текстовый протокол, который позволяет устанавливать значения int32 для некоторых указанных c параметров, отправляя их, например, из P C в 32-битный µ C. Мне нужно проверить, находится ли полученный параметр в диапазоне [INT_MIN, INT_MAX]. Мне нужно создать ошибку, если число находится за пределами этого диапазона. Простое приведение к int и сравнение этого с [INT_MIN, INT_MAX] не удастся.

Моя текущая идея:
1. приведение строки к числу,
2. приведение числа к строке,
3. сравнение полученной и приведенной строки с 2.,

Если оба равны, число в строке должно быть действительным значением int32.

Есть ли другие предложения или идеи? Thx

Ответы [ 2 ]

2 голосов
/ 26 марта 2020

Как проверить строку, которая является числом для >INT_MAX или <INT_MIN ...

, чтобы проверить, находится ли полученный параметр в диапазоне [INT_MIN, INT_MAX]

«приведение строки к числу» и «приведение числа к строке» не будут работать как int тест. Код должен преобразовать .

long int strtol(const char *nptr, char **endptr, int base) с готовностью делает это. @ PSkocik

#include <ctype.h>
#include <limits.h>
#include <stdlib.h>

bool test_int(const char *s, int *int_result) {
  char *endptr;   // Location where conversion stopped
  errno = 0;      // Need to clear, to test for overflow later
  long n = strtol(s, &endptr, 0);
  if (errno == ERANGE) {
    return false; // Outside long range
  }

  // In case int is narrower than long
  #if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
  if (n < INT_MIN || n > INT_MAX) {
      return false; // Outside int range
  }
  #endif

  if (s == endptr) {
    return false; // No conversion
  }

  // Perhaps allow trailing white-space?
  while (isspace((unsigned char) *endptr)) {
    endptr++;
  }

  if (*endptr != '\0') {
    return false; // Extra junk at the end
  }

  *int_result = (int) n;
  return true;
}

В качестве составной части синтаксического анализатора протокола с различными целыми числами ранжирования рассмотрим тест общего назначения подписанный :

bool test_integer(const char *s, intmax_t *integer, intmax_t mn, intmax_t mx) {
  char *endptr; 
  errno = 0;
  *integer = strtoimax(s, &endptr, 0);
  if (errno == ERANGE || *integer < mn || *integer > mx) {
    *integer = (*integer < mn) ? mn : mx;
    errno == ERANGE;
    return false; // Outside intmax_t range
  }

  while (isspace((unsigned char) *endptr)) {
    endptr++;
  }

  if (s == endptr || *endptr != '\0') {
    return false; // No conversion or junk at end
  }

  return true;
}

// Sample usage for int
intmax_t im;
if (test_integer(s, &im, INT_MIN, INT_MAX))  {
  int i = (int) im;
  ...
0 голосов
/ 26 марта 2020

Для фиксированного числа чисел времени компиляции эта проверка может быть эффективно выполнена непосредственно в строке. Более того, учитывая, что по первому символу вы можете напрямую определить, является ли он отрицательным или нет.

После того, как вы перейдете к проверке MAX_INT или MIN_INT, два числа вы можете преобразовать в строку cmp либо во время разработки или один раз во время выполнения вы можете легко сделать следующее:

  1. Проверить, превышает ли длина входа длину cmp -> fail
  2. Если оно короче -> pass
  3. Если оно равно, сравнивать обе строки по компонентам, пока символы совпадают. Первый символ во входной строке, который сравнивается строго больше, чем cmp, приводит к -> fail
  4. В противном случае, ввод в порядке и вы можете его преобразовать.

Да, это добавляет дополнительные ветви l oop и n + 1, в худшем случае, если вы подтвердите строку в этом проходе, вы можете опустить все ветви на этапе преобразования, поэтому вам придется заплатить только одну дополнительную ветку .

...