Хорошая практика кодирования C / этикет для проверки целостности

Вопрос из двух частей;

Я исхожу из языка высокого уровня, так что это вопрос формы, а не функции;

Я написал функцию isnumeric(), которая принимает char[] и возвращает 1, если строка является числом, используя функцию isdigit() в ctype. Подобные функции встроены в другие языки, и я всегда использовал что-то подобное для проверки целостности данных перед преобразованием их в числовой тип. Главным образом потому, что некоторые функции преобразования языков плохо работают, если вы пытаетесь преобразовать нечисловую строку в целое число.

Но это похоже на то, что kludge приходится делать все эти циклы, чтобы компенсировать отсутствие строк в C, что ставит первую часть вопроса;

Является ли приемлемой практикой в ​​C перехватывать возврат 0 от atoi() вместо проверки целостности данных перед вызовом atoi()? Способ работы atoi() (и других функций ascii to xx), похоже, хорошо подходит для полного исключения проверки целостности. Конечно, было бы эффективнее просто пропустить проверку.

Вторая часть вопроса: Существует ли функция C или общая библиотека для проверки числовой целостности строки? (под строкой я, конечно, имею в виду char[])

5 ответов

Решение

Является ли приемлемой практикой в ​​C перехватывать возврат 0 от atoi() вместо проверки целостности данных перед вызовом atoi()?

Никогда не поймайте ошибку, если она не указывает на программную ошибку, которая не может произойти, если в коде нет ошибки. Всегда возвращайте какой-либо результат ошибки в случае ошибки. Посмотрите на OpenBSD strtonum функция для того, как вы могли бы разработать такой интерфейс.

Вторая часть вопроса: Существует ли функция C или общая библиотека для проверки числовой целостности строки? (под строкой я, конечно, имею в виду char[])

Никогда не используйте atoi если вы пишете программу без проверки ошибок как atoi не проверяет ошибки strtol Семейство функций позволяет проверять наличие ошибок. Вот простой пример того, как вы можете их использовать:

int check_is_number(const char *buf)
{
    const char *endptr;
    int errsave = errno, errval;
    long result;

    errno = 0;
    result = strtol(buf, &endptr, 0);
    errval = errno;
    errno = errsave;

    if (errval != 0)
        return 0; /* an error occured */

    if (buf[0] == '\0' || *endptr != '\0')
        return 0; /* not a number */

    return 1;
}

Смотрите страницу руководства, на которую ссылались ранее, чтобы узнать, как третий аргумент strtol (база) влияет на то, что он делает.

errno установлен в ERANGE если значение выходит за пределы диапазона для требуемого типа (т.е. long). В этом случае возвращаемое значение LONG_MAX или же LONG_MIN,

Является ли приемлемой практикой в ​​C перехватывать возврат 0 от atoi() вместо проверки целостности данных перед вызовом atoi()?

Нет. @FUZxxl хорошо на это отвечает.

Существует ли функция C или общая библиотека для проверки числовой целостности строки?

В C преобразование строки в число и проверка, чтобы проверить, является ли преобразование допустимым, обычно выполняется вместе. Используемая функция зависит от типа искомого числа. "1.23" будет иметь смысл для типа с плавающей запятой, но не для целого числа.

// No error handle functions
int atoi(const char *nptr);
long atol(const char *nptr);
long long atoll(const char *nptr);
double atof(const char *nptr);

// Some error detection functions
if (sscanf(buffer, "%d", &some_int) == 1) ...
if (sscanf(buffer, "%lf", &some_double) == 1) ...

// Robust methods use
long               strtol(   const char *nptr, char ** endptr, int base);
long long          strtoll(  const char *nptr, char ** endptr, int base);
unsigned long      strtoul(  const char *nptr, char ** endptr, int base);
unsigned long long strtoull( const char *nptr, char ** endptr, int base);
intmax_t           strtoimax(const char *nptr, char ** endptr, int base);
uintmax_t          strtoumax(const char *nptr, char ** endptr, int base);
float              strtof(   const char *nptr, char ** endptr);
double             strtod(   const char *nptr, char ** endptr);
long double        strtold(  const char *nptr, char ** endptr);

Эти надежные методы используют char ** endptr сохранить строку строки, где сканирование остановлено. Если числовые данные не найдены, то *endptr == nptr, Таким образом, общий тест может

char *endptr;
y = strto...(buffer, ..., &endptr);
if (buffer == endptr) puts("No conversion");
if (*endptr != '\0') puts("Extra text");

Если диапазон был превышен, все эти функции устанавливают глобальную переменную errno = ERANGE; и вернуть минимальное или максимальное значение для типа.

errno = 0;
double y = strtod("1.23e10000000", &endptr);
if (errno == ERANGE) puts("Range exceeded");

Целочисленные функции позволяют выбор радиуса от основания 2 до 36. Если 0 используется, ведущая часть строки "0x", "0X", "0", other -> база 16, 16, 8, 10.

long y = strtol(buffer, &endptr, 10);

Прочитайте спецификацию или страницу помощи для более подробной информации.

Если метод преобразования возвращает индикацию ошибки (в отличие от бананов, если возникает ошибка, или не предоставляя окончательного средства для проверки того, произошла ли ошибка), то на самом деле нет необходимости проверять, является ли строка числовой, прежде чем пытаться преобразовать Это.

Имея это в виду, используя atoi() не очень хорошая функция для использования, если вам нужно проверять ошибки при конвертации. Ноль будет возвращен для нулевого ввода, а также при ошибке, и нет способа проверить, почему. Лучшая функция для использования (если вы хотите прочитать целое значение) strtol(), Хотя strtol() возвращает целое число ноль, а также возвращает информацию, которую можно использовать для проверки на наличие ошибок. Например;

long x; 
char *end;

x = strtol(your_string, &end, 10);
if (end == your_string)
{
     /*  nothing was read due to invalid character or the first 
         character marked the end of string */
}
else if (*end != '\0`)
{
    /*  an integral value was read, but there is following non-numeric data  */
}

Во-вторых, есть альтернативы использованию strtol(), хотя и включает в себя больше накладных расходов. Возвращаемые значения из sscanf() (и, фактически, все функции в scanf() семья) можно проверить на наличие ошибок.

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

int IsNumeric(char *your_string)
{
     /*  This has undefined behaviour if your_string is not a C-style string
           It also deems that a string like "123AB" is non-numeric
     */
     long x; 
     char *end;

     x = strtol(your_string, &end, 10);
     return !(end == your_string || *end != '\0`);
}

Никаких (явных) циклов ни в одном из указанных выше вариантов.

ОП позже соединился:

Я ищу способ определить, содержит ли строка ТОЛЬКО базовые 10 цифр или десятичную или запятую. Так что, если строка 100,000.01, я хочу положительный результат от func. Любые другие символы ascii в любом месте строки приведут к отрицательному возвращаемому значению.

Если это все ваши интересы, используйте;

if (buffer[strspn(buffer, "0123456789.,")] == '\0') return 0; // Success
else return -1; // Failure

Вам, вероятно, не нужна функция, чтобы проверить, является ли строка числовой. Скорее всего, вам нужно будет преобразовать строку в число, так что просто сделайте это. Затем проверьте, если преобразование прошло успешно.

long number;
char *end;
number = strtol(string, &end, 10);
if ((*string == '\0') || (*end != '\0'))
{
    // empty string or invalid number
}

второй аргумент strtol используется для указания места окончания синтаксического анализа (первый нечисловой символ) Этот персонаж будет \0 если мы достигли конца строки. Если вы хотите разрешить другие символы после числа (например, ), ты можешь использовать switch проверить это.

strtol работает с long целые числа. Если вам нужен другой тип, вам следует обратиться к странице справочника: man 3 strtol, Для чисел с плавающей точкой вы можете использовать strtod,

Не перехватывайте, если логика программы допускает, что строка не является числовой (например, если она исходит от пользователя или файла).

Другие вопросы по тегам