В чем разница между sscanf или atoi для преобразования строки в целое число?
gcc 4.4.4 c89
что лучше преобразовать строку в целочисленное значение.
Я пробовал 2 различных метода atoi и sscanf. Оба работают, как и ожидалось.
char digits[3] = "34";
int device_num = 0;
if(sscanf(digits, "%d", &device_num) == EOF) {
fprintf(stderr, "WARNING: Incorrect value for devicen");
return FALSE;
}
или с помощью atoi
device_num = atoi(digits);
Я думал, что sscanf будет лучше, как вы можете проверить на наличие ошибок. Однако atoi не делает никаких проверок.
6 ответов:
у вас есть 3 варианта:
atoiэто, вероятно, самый быстрый, если вы используете его в критически важном для производительности коде, но он не сообщает об ошибках. Если строка не начинается с целого числа, она возвращает 0. Если строка содержит мусор после целого числа, она преобразует начальную часть и игнорирует остальные. Если число слишком велико, чтобы вписаться в
intэто поведение неопределенный.
sscanfнекоторые сообщения об ошибках, и у вас есть много гибкости для того, какой тип хранить (подписанные / неподписанные версии
char/short/int/long/long long/size_t/ptrdiff_t/intmax_t).возвращаемое значение-это количество успешных преобразований, поэтому сканирование для
"%d"возвращает 0, если строка не начинается с числа. Вы можете использовать"%d%n"чтобы сохранить индекс первого символа после целого числа, которое читается в другой переменной, и тем самым проверить смотрите, если вся строка была преобразована или если есть мусор после этого. Однако, какatoi, поведение при переполнении целого числа не определено.
strtolи семьейнадежные отчеты об ошибках, при условии, что вы установили
errnoдо 0 перед вызовом. Возвращаемые значения указываются при переполнении иerrnoбудет установлен. Вы можете выбрать любую счисления от 2 до 36, или указать 0 в качестве базы для автоматической интерпретации ведущих0xи0как hex и восьмеричный, соответственно. Выбор типа для преобразования в подписанные / неподписанные версииlong/long long/intmax_t.Если вам нужен меньший тип, вы всегда можете сохранить результат во временном
longилиunsigned longпеременная и проверьте переполнение самостоятельно.поскольку эти функции принимают указатель на аргумент указателя, вы также получаете указатель на первый символ, следующий за преобразованным целым числом, бесплатно, поэтому вы можете сказать, была ли вся строка целым числом или проанализировать последующие данные в строке, если это необходимо.
лично я бы рекомендовал
strtolсемья большинство целей. Если вы делаете что-то быстро и грязно, atoi может удовлетворить ваши потребности.в стороне, иногда я нахожу, что мне нужно разобрать числа, где ведущие пробелы, знак и т. д. не должны быть приняты. В этом случае довольно чертовски легко свернуть свой собственный цикл for, например.,
for (x=0; (unsigned)*s-'0'<10; s++) x=10*x+(*s-'0');или вы можете использовать (для робастность):
if (isdigit(*s)) x=strtol(s, &s, 10); else /* error */
*scanf()семейство функций возвращает количество преобразованных значений. Поэтому вы должны проверить, чтобы убедитьсяsscanf()возвращает 1 в вашем случае.EOFвозвращается для "input failure", что означает, чтоssacnf()никогда не вернетсяEOF.на
sscanf(), функция должна проанализировать строку формата, а затем декодировать целое число.atoi()не имеет таких накладных расходов. Оба страдают от проблемы, что значения вне диапазона приводят к неопределенному поведению.вы следует использовать
strtol()илиstrtoul()функции, которые обеспечивают гораздо лучшее обнаружение ошибок и проверку. Они также дают вам знать, если вся строка была потреблена.если вы хотите
int, вы всегда можете использоватьstrtol(), а затем проверить возвращаемое значение, чтобы увидеть, если он находится междуINT_MINиINT_MAX.
To @R.. Я думаю, что это не достаточно, чтобы проверить
errnoдля обнаружения ошибок вstrtolзвонок.long strtol (const char *String, char **EndPointer, int Base)вам также нужно проверить
EndPointerдля ошибок.
Объединение Р.. и PickBoy отвечает для краткости
long strtol (const char *String, char **EndPointer, int Base) // examples strtol(s, NULL, 10); strtol(s, &s, 10);
когда нет проблем с недопустимым строковым вводом или проблемами диапазона, используйте самый простой:
atoi()в противном случае метод с лучшим обнаружением ошибки/диапазона не является ни
atoi(), ниsscanf(). это хороший ответ все готовые детали отсутствие ошибок сatoi()и некоторые проверка ошибок с помощьюsscanf().
strtol()является наиболее строгой функцией при преобразовании строки вint. Но это только начало. Ниже приведены подробные примеры, чтобы показать правильное использование и поэтому причина такого ответа после принят.// Over-simplified use int strtoi(const char *nptr) { int i = (int) strtol(nptr, (char **)NULL, 10); return i; }это как
atoi()и не использовать функции обнаружения ошибокstrtol().полностью использовать
strtol(), есть различные функции, чтобы рассмотреть:
определение преобразование примеры:
"xyz"или""или"--0"? В этих случаяхendptrбудет соответствоватьnptr.char *endptr; int i = (int)strtol(nptr, &endptr, 10); if (nptr == endptr) return FAIL_NO_CONVERT;должна ли вся строка преобразовываться или только ведущая часть: Is
"123xyz"ОК?char *endptr; int i = (int)strtol(nptr, &endptr, 10); if (*endptr != '') return FAIL_EXTRA_JUNK;определить, если значение было настолько большим, то результат не представляется в виде
longкак"999999999999999999999999999999".errno = 0; long L = strtol(nptr, &endptr, 10); if (errno == ERANGE) return FAIL_OVERFLOW;определить, если значение было вне диапазона, чем
int, но неlong. Еслиintиlongимейте такой же ряд, этот тест нет необходимый.long L = strtol(nptr, &endptr, 10); if (L < INT_MIN || L > INT_MAX) return FAIL_INT_OVERFLOW;некоторые реализации выходят за рамки стандарта C и устанавливают
errnoпо дополнительным причинам, таким как errno в EINVAL в случае, если преобразование не было выполнено илиEINVALзначение базового параметра недопустимо.. Лучшее время для проверки этихerrnoзначения зависит от реализации.положить все это вместе: (настроить на ваш потребности)
#include <errno.h> #include <stdlib.h> int strtoi(const char *nptr, int *error_code) { char *endptr; errno = 0; long i = strtol(nptr, &endptr, 10); #if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX if (errno == ERANGE || i > INT_MAX || i < INT_MIN) { errno = ERANGE; i = i > 0 : INT_MAX : INT_MIN; *error_code = FAIL_INT_OVERFLOW; } #else if (errno == ERANGE) { *error_code = FAIL_OVERFLOW; } #endif else if (endptr == nptr) { *error_code = FAIL_NO_CONVERT; } else if (*endptr != '') { *error_code = FAIL_EXTRA_JUNK; } else if (errno) { *error_code = FAIL_IMPLEMENTATION_REASON; } return (int) i; }
Примечание: все упомянутые функции позволяют ведущие пробелы, необязательный ведущий знак характер и зависит от locale изменить. Для более строгого преобразования требуется дополнительный код.
Примечание: не-OP название изменить перекошенный акцент. Этот ответ лучше относится к оригинальному заголовку "преобразовать строку в целое число sscanf или atoi"
Если пользователь вводит 34abc и вы передаете их atoi, он вернет 34. Если вы хотите проверить введенное значение, то вы должны использовать isdigit на введенной строке итеративно
Comments