Как использовать `strtoul` для разбора строки, где может быть допустимым ноль? - PullRequest
0 голосов
/ 13 декабря 2018

В соответствии с документацией для strtoul относительно его возвращаемого значения ...

Эта функция возвращает преобразованное целое число в виде длинного целого значения.Если никакое допустимое преобразование не может быть выполнено, возвращается нулевое значение.

Что, если я анализирую предоставленную пользователем строку «0», где для моего приложения «0» может бытьдействительная запись?В этом случае кажется, что я не могу определить, используя strtoul, было ли выполнено правильное преобразование.Есть ли другой способ справиться с этим?

Ответы [ 4 ]

0 голосов
/ 13 декабря 2018

Рассмотрим следующую функцию:

#include <stdlib.h>
#include <errno.h>
/* SPDX-Identifier: CC0-1.0 */

const char *parse_ulong(const char *src, unsigned long *to)
{
    const char    *end;
    unsigned long  val;

    if (!src) {
        errno = EINVAL;
        return NULL;
    }

    end = src;
    errno = 0;
    val = strtoul(src, (char **)(&end), 0);
    if (errno)
        return NULL;
    if (end == src) {
        errno = EINVAL;
        return NULL;
    }

    if (to)
       *to = val;

    return end;
}

Эта функция анализирует длинную без знака в строке src, возвращая указатель на первый неразобранный символ в src, а длинная без знака сохраняется в *to.Если есть ошибка, функция вернет NULL с errno, установленным для указания ошибки.

Если вы сравните функцию с man 3 strtoul, вы увидите, что она обрабатывает все случаи ошибокправильно, и возвращает ненулевое значение, только когда src возвращает действительный беззнаковый long.Особенно см. Раздел «Примечания».Также обратите внимание на то, как обрабатываются отрицательные числа.

Этот же шаблон работает для strtol(), strtod(), strtoull().

0 голосов
/ 13 декабря 2018

Одним из решений было бы передать адрес указателя char и проверить, указывает ли он на начало строки:

char *str = "0";
char *endptr;
unsgined long x = strtoul(str, &endptr, 10);

if(endptr == str)
{
    //Nothing was read
}
0 голосов
/ 13 декабря 2018

Как использовать strtoul для анализа строки, где может быть действительным ноль?

Любое значение, возвращаемое из strtoul(), может быть из ожидаемого строкового ввода или из другой не очень ожидаемые строки.Дополнительные тесты полезны.

Следующие строки все возвращают 0 из strtoul()

  • OK "0", "-0", "+0"
  • Не ОК "", "abc"
  • Обычно считается ОК: " 0"
  • ОК или не ОК в зависимости от целей: "0xyz", "0 ", "0.0"

strtoul() имеет различные режимы обнаружения.

int base = 10;
char *endptr;  //  Store the location where conversion stopped

errno = 0;
unsigned long y = strtoul(s, &endptr, base);

if (s == endptr) puts("No conversion");      // "", "abc"
else if (errno == ERANGE) puts("Overflow");
else if (*endptr) puts("Extra text after the number"); // "0xyz", "0 ", "0.0"
else puts("Mostly successful");

Что еще не обнаружено.

  • Отрицательный вход.strtoul() эффективно оборачивается так, что strtoul("-1", 0, 10) == ULONG_MAX). Эта проблема часто упускается при кратком рассмотрении документации.

  • Допускается начальный пробел.Это может или не может быть желательным.


Чтобы также обнаружить отрицательные значения:

// find sign
while (isspace((unsigned char) *s)) {
  s++;
}
char sign = *s;

int base = 10;
char *endptr;  //  Store the location where conversion stopped
errno = 0;
unsigned long y = strtoul(s, &endptr, base);

if (s == endptr) puts("No conversiosn");
else if (errno == ERANGE) puts("Overflow");
else if (*endptr) puts("Extra text after the number"); 
else if (sign == '-' && y != 0) puts("Negative value"); 
else puts("Successful");
0 голосов
/ 13 декабря 2018

Читать далее справочную страницу :

Поскольку strtoul() может законно вернуть 0 или ULONG_MAX (ULLONG_MAX для strtoull()) при обоих успехахВ случае сбоя вызывающая программа должна установить errno в 0 перед вызовом, а затем определить, произошла ли ошибка, проверив, имеет ли errno ненулевое значение после вызова.

Также, для обработки другого сценария, где никакие цифры не были прочитаны на входе.Если это происходит, strtol() устанавливает значение *endptr равным nptr.Таким образом, вы также должны проверить, что значения указателя сравниваются или нет.

...