Atoi против atol против strtol против strtoul против sscanf

Я пытаюсь разобраться в анализируемой командной строке, какая функция лучше всего конвертировать десятичное, шестнадцатеричное или восьмеричное число в int лучшее - не зная ввода заранее.

Цель состоит в том, чтобы использовать единственную функцию, которая распознает различные типы входов и присваивает ее целочисленному (int) значению, которое затем можно использовать так:

./a.out 23 0xC4 070

может печатать

23
196 /*hexadecimal*/
56  /*octal*/

Единственная проблема, которую я вижу, - это разбор, чтобы найти разницу между десятичным целым и восьмеричным.

Боковой вопрос, стабилен ли он для преобразования строки в целое число для использования?

Ответ 1

какая функция будет лучше всего преобразовать десятичное, шестнадцатеричное или восьмеричное число в целое число (?)

Чтобы преобразовать такой текст в int, рекомендуем long strtol(const char *nptr, char **endptr, int base); с дополнительными тестами при конвертации в int, если это необходимо.

Используйте 0 в качестве base для оценки ранних символов в преобразовании рулевого управления как базы 10, 16 или 8. @Mike Holt

0x or 0X followed by hex digits--> hexadecimal  
0 --> octal  
else --> decimal  

Образец кода

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

int mystrtoi(const char *str) {
  char *endptr;
  errno = 0;
  //                                   v--- determine conversion base
  long long_var = strtol(str, &endptr, 0);
  //   out of range   , extra junk at end,  no conversion at all   
  if (errno == ERANGE || *endptr != '\0' || str == endptr) {
    Handle_Error();
  }

  // Needed when 'int' and 'long' have different ranges
  #if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
  if (long_var < INT_MIN || long_var > INT_MAX) {
    errno = ERANGE;
    Handle_Error();
  }
  #endif

  return (int) long_var;
}

Атой против Атол против Стрэтол против Стрэтул против Скэнф

atoi()
Pro: Очень просто.
Pro: конвертировать в int.
Pro: В стандартной библиотеке C
Pro: быстро.
Con: нет обработки ошибок.
Con: не обрабатывать ни шестнадцатеричное, ни восьмеричное.

atol()
Pro: просто.
Pro: В стандартной библиотеке C
Pro: быстро.
Con: Конвертирует в long, не int который может отличаться по размеру.
Con: нет обработки ошибок.
Con: не обрабатывать ни шестнадцатеричное, ни восьмеричное.

strtol()
Pro: просто.
Pro: В стандартной библиотеке C
Pro: Хорошая обработка ошибок.
Pro: быстро.
Pro: Может обрабатывать двоичные файлы.
Con: Конвертировать в long, а не int который может отличаться по размеру.

strtoul()
Pro: просто.
Pro: В стандартной библиотеке C
Pro: Хорошая обработка ошибок.
Pro: быстро.
Pro: Может обрабатывать двоичные файлы.
---: появляется, чтобы не жаловаться на отрицательные числа.
Con: конвертирует в unsigned long, не int который может отличаться по размеру.

sscanf(..., "%i",...)
Pro: В стандартной библиотеке C
Pro: конвертирует в int.
---: средняя сложность.
Против: Потенциально медленно.
Con: ОК, обработка ошибок (переполнение не определено).

Все страдают/выигрывают от настроек locale. §7.22.1.4 6 "В отличие от локали" C "могут приниматься дополнительные формы предметной последовательности, специфичные для локали".


Дополнительные кредиты:
@Jonathan Leffler: errno тест на ERANGE, atoi() только для десятичных чисел, обсуждение errno -многопоточности.
@Marian Скорость выпуска.
@Kevin Библиотека инклюзивности.


Для преобразования short, signed char и т.д. Рассмотрим strto_subrange().

Ответ 2

Разумно рассмотреть strtol() и strtoul() (или strtoll() или strtoull() от <stdlib.h>, или, возможно, strtoimax() или strtoumax() от <inttypes.h>), если вы беспокоитесь об условиях ошибки, Если вас не волнуют условия ошибки при переполнении, любой из них может быть использован. Ни atoi(), ни atol(), ни sscanf() не дает вам контроля, если значения переполняются. Кроме того, ни atoi(), ни atol() не поддерживают шестнадцатеричные или восьмеричные входы (так что вы не можете использовать их для удовлетворения ваших требований).

Обратите внимание, что вызов функций strtoX() не является тривиальным. Вы должны установить errno в 0 перед их вызовом и передать указатель, чтобы получить конечное местоположение, и тщательно проанализировать, чтобы узнать, что произошло. Помните, что все возможные возвращаемые значения из этих функций являются допустимыми выходами, но некоторые из них могут также указывать недопустимые входы - и errno, а конечный указатель поможет вам различать их все.

Если вам нужно преобразовать в int после чтения значения, используя, скажем, strtoll(), вы можете проверить диапазон возвращаемого значения (сохраненный в long long) в диапазоне, определенном в <limits.h>, для int: INT_MIN и INT_MAX.

Подробнее см. в моем ответе: Исправить использование strtol().

Обратите внимание, что ни одна из этих функций не указывает вам, какое преобразование было использовано. Вам нужно будет проанализировать строку самостоятельно. Причудливая нота: знаете ли вы, что в источнике C нет десятичного числа 0; когда вы пишете 0, вы пишете восьмеричную константу (потому что ее первая цифра равна 0). Нет никаких практических последствий для этой мелочи.