Strtod   strtoul преобразовать из ац вида


Содержание

Strtod   strtoul преобразовать из а/ц вида

Строка должна начинаться с произвольного количества пустых символов (определяемых при помощи isspace (3)) , затем должен идти знак `+’ или `-‘ (если есть). Если base равно нулю или 16-и, то строка может начинаться с приставки `0x’, что означает использование шестнадцатеричной системы исчисления; иначе, если base равно нулю, используется десятичная система счисления, кроме случая, когда последующий символ также равен `0′: тогда используется восьмеричная система исчисления.

Остаток строки, таким образом, конвертируется в беззнаковое целое число. Этот процесс останавливается, если в строке встречается некорректное значение (например, не соответствующая системе исчисления цифра). Символ `A’ в верхнем или нижнем регистре означает 10, `B’ означает 11 и так далее (до `Z’, означающей 35).

Если значение endptr не NULL, то strtol() записывает адрес первого некорректного значения в *endptr . Если в строке вообще нет цифр, то strtol() сохраняет начальное значение nptr в *endptr (и возвращает 0). Соответственно, если *nptr не равно `\0′, а **endptr равно `\0′ по возвращении, то вся строка состоит из корректных символов.

Функция strtoull() работает так же, как и strtoul() , но возвращает целое число типа unsigned long long int.

ВОЗВРАЩАЕМЫЕ ЗНАЧЕНИЯ


НАЙДЕННЫЕ ОШИБКИ

Некоторые реализации могут также устанавливать errno в EINVAL в случае, когда преобразование не было выполнено (не было встречено цифр и возвращен 0).

Преобразование строки в число и обратно

Задача Преобразовать строку символов в соответствующее число и обратно.

При составлении программ часто возникает задача получения данных, например, введенных в поле редактирования в числовой форме и вывод результата в текстовое поле.
Число, которое принимает участие в вычислительных процедурах, должно быть представлено в виде строки символов, понятных пользователю, для вывода на экран.
Например, число 235 состоит из трех символов — ‘2’, ‘3’, ‘5’.
Целью рассмотрения данной задачи является приведение символьной строки к соответствующему ей числовому виду.
Для этого нужно разбить символьную строку на значащие разряды и выбрать цифры, соответствующие каждому значащему разряду.

Каждый символ цифры имеет соответствующий ему код в базовой таблице кодировки:

Символ цифры Десятичный код Шестнадцатеричный код Двоичный код
48 0x30 0011 0000
1 49 0x31 0011 0001
2 50 0x32 0011 0010
3 51 0x33 0011 0011
4 52 0x34 0011 0100
5 53 0x35 0011 0101
6 54 0x36 0011 0110
7 55 0x37 0011 0111
8 56 0x38 0011 1000
9 57 0x39 0011 1001

В соответствии с приведенной таблицей, значащая часть каждого символа цифры содержится в младшей тетраде битов (младших четырех разрядах). Для получения цифры, соответствующей символу, достаточно произвести операцию:
n = s & 0x0F;
где n — значащая цифра, s — символ цифры. Маска 0x0F позволяет оставить только младшие 4 значащих разряда. Старшие 4 разряда становятся равны 0.

При решении обратной задачи — представления числа в виде текстовой строки — каждая цифра значащего разряда преобразуется в соответствующий ей символ с помощью операции:
s = n | 0x30;
Указанная операция добавляет двоичное значение 0011 в старшие 4 разряда, тем самым формируя код символа из соответствующей значащей цифры.

Описание функций языка Си

All | _ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

strtod – преобразование строки в число типа double.

#include
double strtod (const char *str, char **endstr);

str – указатель на строку для преобразования.
endstr – указатель на переменную, в которую будет помещен указатель на непреобразованный остаток строки или на начало строки str, если преобразование не удалось или вся строка преобразована.

При успешном завершении функции возвращается результат преобразования – число типа double, а по адресу указанному в переменной endstr записывается указатель на оставшуюся непреобразованную часть строки или указатель на начало строки, если вся строка была преобразована.

Если преобразование не может быть выполнено, то возвращается 0, а по адресу указанному в переменной endstr записывается указатель на начало строки str.

Если в результате преобразования получено слишком большое по абсолютной величине число, то будет возвращено плюс или минус HUGE_VAL в зависимости от знака числа и переменной errno будет присвоено значение [ERANGE]. Если получено слишком маленькое по абсолютной величине число, то будет возвращен 0 и переменной errno будет присвоено значение [ERANGE]. При этом по адресу указанному в переменной endstr записывается указатель на оставшуюся непреобразованную часть строки или указатель на начало строки, если вся строка была преобразована.

Функция преобразует строку (с числом с плавающей точкой) в число типа double. Число с плавающей точкой — форма представления действительных чисел, в которой число хранится в форме мантиссы и показателя степени, например 123.45*e6, где 123.45 – мантисса, 6 – порядок.

Преобразуемая строка должна иметь вид: [pr] [zn] [dс] [.] [dd] [e[znp]dp]

[pr] – пробел. В начале преобразуемой строки пробел необязателен. Если в одной строке содержится несколько чисел в символьном формате, то они должны быть разделены пробелами.

[zn] – знак мантиссы + или — , если знак отсутствует, то мантисса считается положительной.

[dс] – десятичные цифры целой части мантиссы, если данные цифры отсутствует, то целая часть мантиссы считается нулевой.

[.] – десятичная точка (разделитель целой и дробной части мантиссы), если данный знак отсутствует, то мантисса содержит только целую часть.

[dd] — десятичные цифры дробной части мантиссы, если данные числа отсутствуют, то мантисса содержит только целую часть.

[e] – символ e или E, если данный символ отсутствует, то число с плавабющей точкой не содержит порядок (содержит нулевой порядок).

[znp] – знак порядка + или — , если знак отсутствует, то порядок считается положительным.

[dp] – десятичные цифры порядка, если цифры отсутствуют порядок равен 0.

Наличие либо целой, либо дробной части числа мантиссы обязательно, порядок может полностью отсутствовать, но если он указан, обязательно перед порядком должен идти символ e или E. Пробелы внутри числа с плавающей точкой недопустимы.

Примеры записи числа с плавающей точкой: +123.45e6, +123.45E6, 123E-6, -123E6, -.45e6, +123.45 и т.д.

В одной преобразуемой строке может быть несколько чисел с плавающей точкой, в этом случае каждое число должно быть отдалено от другого пробелом.

В примере строка «+123.45e6 +123.45E6 0 123E-6 -123E6 -.45e6 +123.45» преобразуется в семь чисел типа double и результат выводится на консоль.

Вывод в консоль:

123450000.000000
123450000.000000
0.000000
0.000123
-123000000.000000
-450000.000000
123.450000

Несколько способов преобразования строки в число и обратно / C++ для начинающих / C++

Несколько способов преобразования строки в число и обратно.

Очень часто в форуме всплывает один и тот же вопрос — «Как преобразовать char*/char[]/CString/string в число?» или, несколько реже «Как преобразовать число в char*/char[]/CString/string». В этой небольшой статье я попытаюсь на него ответить максимально полным образом.

Преобразование строки в число

Выполнить преобразование строки в число можно многими способами — выбор конкретного зависит от ваших целей на момент написания кода. Есть штатные способы — ряд библиотечных функций, есть более изощренные, есть совсем уж извращенные годные разве что для экзерсисов в области программирования. Начну с самых простых.
Первый, и, наверное, самый распространенный, но далеко не самый лучший — использование штатных библиотечных функций atoi, atof, atol. Эти функции входит в стандартную библиотеку языка и присутствует в любом компиляторе. Их объявления выглядит так:

На вход они принимают указатель на строку, завершенную нулем, а возвращают — число, которое этой строкой описывается. atoi и atol воспринимают следующий формат числа:
[пробелы][знак]цифры
а atof, соответственно:
[пробелы][знак][цифры][.цифры][<d | | e | E >[знак]цифры]
Здесь пробелы — любой из знаков пробела, табуляции (\t), вертикальной табуляции (\v) — они игнорируются. Знак — символ ‘+’ или ‘-‘. Если не указан, то считается, что число положительное. Цифры — символы от ‘0’ до ‘9’. Для числа с плавающей точкой, если не указаны цифры до знака ‘.’, то должна быть указана хотя бы одна цифра после него. После дробной части может быть указана экспонента, следующая за одним из символов-префиксов экспоненты.
Основной недостаток этих функций заключается в том, что они никак не сигнализируют об ошибке, если таковая произошла в процессе разбора переданной строки. Под ошибкой я понимаю невозможность корректно разобрать переданный набор символов — несоответствие его формату или по иным причинам.
Эту проблему решает следующий набор библиотечных функций, также включенных в стандартную библиотеку:

Эти функции имеют следующие отличия от предыдущей группы:

  • Через параметр end_ptr они возвращают указатель на первый символ, который не может быть интерпретирован как часть числа.
  • Контролируют переполнение и, если таковое произошло, сигнализируют об этом выставлением значения переменной errno в ERANGE, а также возвращают, соответственно, LONG_MAX/LONG_MIN, ULONG_MAX/ULONG_MIN и +/-HUGE_VAL в зависимости от знака числа в переданной строке.
  • strtod использует информацию о текущих установленных (через setlocale) региональных настройках, таким образом может корректно интерпретировать числа с символом ‘,’ в качестве разделителя целой и дробной части.
  • Для функций strtol и strtoul можно указать основание системы счисления. При этом, если в качестве основания передан 0, то основание определяется автоматически по первым символам числа. Если это символ ‘0’, а сразу за ним идет цифра — то основание принимается равным 8. Если первая цифра ‘0’, а за ней идет символ ‘x’ или ‘X’, то основание принимается равным 16. В остальных случаях основание принимается равным 10. В качестве цифр в этом случае можно использовать символы ‘0’ — ‘9’ и ‘A’ — ‘Z’ или ‘a’ — ‘z’, а основание может принимать значения от 2 до 36.
  • Если варианты этих функций для преобразования чисел, описанных unicode-строками. Они, соответственно, носят названия wcstolwcstoul и wcstod.

Типичное использование этих функций такое:

CODE
char* end_ptr;
long val = strtol(str, &end_ptr, 10);
if (*end_ptr)
<
// Сигнализируем об ошибке в строке
>
if ((val == LONG_MAX || val == LONG_MIN) && errno == ERANGE)
<
// Сигнализируем о переполнении
>
// Продолжаем штатную работу.

Как можно увидеть, используя эти функции можно получить гораздо больший контроль над преобразованием из строки в число. Для различных преобразований рекомендую пользоваться именно ими.
Говоря о стандартных библиотечных функциях нельзя не упомянуть такую функцию как scanf и ее разновидности — sscanf, fscanf и т. п:

и т. п.
Эту функцию имеет смысл использовать только в случае получения числа от пользователя с консоли (stdin) или из файла. Надо отметить, что функция весьма тяжеловесна (по объему линкуемого к исполняемому модулю библиотечного кода), и далеко не так быстра, как предыдущие, т. к. для преобразования необходимо разобрать форматную строку и соответствующим образом ее проинтерпретировать.
Аналогично можно использовать операторы потокового ввода (‘>>’). В случае написания программ на C++ этот вариант гораздо предпочтительней, чем использования метода scanf, т. к. обеспечивает гораздо больший контроль за типами на этапе компиляции. Ожидаемый формат числа можно указать с помощью флага формата:
dec — целое в десятичном формате;
hex — целое в шестнадцатеричном формате;
oct — целое в восьмеричном формате;
scientific — число с плавающей точкой в экспоненциальном формате;
fixed — число с плавающей точкой в фиксированном формате.
При этом форматы для целых чисел и чисел с плавающей точкой устанавливаются независимо друг от друга.
В случае получения результатов ввода пользователя из строки редактирования (EditBox, CEdit) имеет смысл пользоваться методом GetDlgItemInt:

UINT GetDlgItemInt(HWND hDlg, int itemId, BOOL* pTranslated, BOOL signed)
UNIT CWnd::GetDlgItemInt(int itemId, BOOL* pTranslated, BOOL signed)

Первым параметром в API-вызов передается хэндл диалогового окна, которому принадлежит строка редактирования. Параметр itemId задает идентификатор строки ввода, через pTranslated возвращается признак того, что введенная пользователем строка успешно проинтерпретирована как целое число. Параметром signed задается необходимость получения в качестве результата функции знакового числа.
Для преобразования экземпляра класса CString в число можно воспользоваться любым из предложенных выше методов, т. к. CString без труда преобразуется в указатель на null-terminated-строку. Специальных методов для этого класса разработчиками библиотеки не предусмотрено.
В VCL ситуация чуть лучше. Для класса AnsiString из этой библиотеки определены следующие методы, позволяющие получить число из его строкового представления:
ToInt — простое преобразование строки в целое число;
ToDouble — преобразует строку в число с плавающей точкой. Формат разделительных символов читается из региональных настроек системы.
Оба метода (в случае несоответствие строки формату числа) выбрасывают исключение. Также стоит обратить внимание на метод ToIntDef, который (в случае неудачного преобразования) возвращает значение по умолчанию, переданное ему в качестве параметра.
Вот основные библиотечные и API-функции, которые можно использовать для преобразования строки в число.

Преобразование числа в строку

К сожалению, стандартной специализированной функции (описанной в стандарте языка) для обратного преобразования (числа в строку) не существует. Но это не значит, что таких функций нет в RTL компиляторов. Для преобразования целого числа в строку можно воспользоваться следующими функциями:

эти функции входят в библиотеку компиляторов от Microsoft.
Для компиляторов фирмы Borland можно использовать следующие функции:

Как можно видеть — в компиляторах семейства Microsoft и Borland имена функций отличаются не сильно и формируются по следующему принципу:
[_]исходный_типtoформат_строки. Исходные типы представлены следующими аббревиатурами:
i — int;
l — long;
ul — unsigned long;
i64 — int64;
ui64 — unsigned int 64;
формат строки, соответственно:
a — однобайтный char (ANSI);
w — wide-char (Unicode).
Параметры, принимаемые на вход, имеют следующий смысл. Первый параметр (value) — это значение, которое необходимо преобразовать в строку. Второй (string) — буфер, в который будет помещен результат преобразования. А третий (radix) — основание системы счисления, в которой будет представлено число.
Сказав выше, что нет стандартных функций преобразования числа в строку, я немного лукавил, так как имел в виду именно специализированные функции — аналоги atoi и strtol. К неспециализированным стандартным функциям, выполняющим необходимое преобразование, можно отнести функцию sprintf:

выполняющую форматированный вывод в заданный буфер, а также другие функции из этого семейства. Для необходимого нам преобразования необходимо воспользоваться форматной строкой «%d». При этом будет выполнено стандартное преобразование в десятичное представление числа, аналогичное предыдущим функциям. Формат полученного числа определяется тэгом типа. Существуют следующие тэги типов:
d (или i) — знаковое целое в десятичном формате;
u — беззнаковое целое в десятичном формате;
o — беззнаковое целое в восьмеричном формате;
x (или X) — беззнаковое целое в шестнадцатеричном формате.
Можно использовать также специальные спецификаторы тэгов типа (указываются непосредственно перед тэгом) для того, чтобы указать специальный формат, в котором передано число:
l — передано длинное целое (signed/unsigned long);
h — передано короткое целое (signed/unsigned short);
l64 (для Microsoft) или L (для Borland) — передано 64-битное целое (signed/unsigned __int64).
Вообще говоря, при использовании спецификатора типа h необходимо понимать, что при передаче в функцию printf переменных типа short (по стандарту) продвигаются до типа int. Таким образом, этот спецификатор просто дает указание функции форматирование игнорировать старшие разряды полученного целого параметра.
Функции форматного вывода хороши тем, что им можно явно указать формат, в котором мы хотим получить результат. В частности, форматная строка «%08x» преобразует переданное число в строку, содержащую шестнадцатеричное представление числа шириной 8 символов, при этом, при необходимости, строка будет дополнена слева незначащими нулями до 8 символов. Также достоинством этих функций (перед предыдущей группой) является то, что строка преобразуется в соответствии с установленными для программы (с помощью вызова функции setlocale) региональными настройками (locales).
К основным недостаткам методов форматного вывода можно отнести их низкую скорость работы (на порядок медленней их специализированных аналогов), невозможность преобразования в системы счисления, отличные от восьмеричной, десятичной, и шестнадцатеричной, а также отсутствия контроля за типами и размером переданного буфера, что может приводить к трудновыявляемым ошибкам.
Для перевода чисел с плавающей точкой предназначены следующие методы:

— для Microsoft-компиляторов и

для компиляторов от фирмы Borland.
Назначение функций следующее:
Функция ecvt конвертирует число (value) в заданное (count) количество символов, не выполняя при этом никакого форматирования. Через параметр dec возвращается позиция, с которой начинается дробная часть (позиция десятичной точки), начиная с первого символа строки, а через параметр sign — признак того, что число имеет знак. Тут необходимо сделать ряд следующих замечаний:

  1. Если строковое представление числа уже, чем необходимое количество символов, то число справа дополняется нулями.
  2. сли строковое представление числа шире, чем необходимое количество символов, то возвращаемая через dec позиция находится правее завершающего строку нуля или левее первого символа строки. Выбор знака dec зависит от знака десятичной экспоненты числа. Например, для value= 3.5678e20 и count=6 функция вернет строку «356780», а dec будет равно 21. А для значения 3.5678e-20 и 6, будет возвращено, соответственно, «356780» и -19.
  3. Преобразование производится во внутренний статический буфер, разделяемый с функцией fcvt, по этому необходимо быть осторожным при использовании функции в многопоточной среде.

Функция fcvt отличается от ecvt только тем, что параметр count задает не общее число символов, а число символов после десятичной точки (точность представление числа). При этом строковое представление (по необходимости) дополняется справа нулями до получения нужной ширины. Параметры dec и sign ведут себя аналогичным (как и для ecvt) образом. Для приведенных выше примеров возвращенные значения будут «356780000000000000000000000» и 21, а также «» и -19 соответственно. В последнем случае возвращенная пустая строка означает, что строковое представление содержит только нули.
Функция gcvt преобразует заданное число (value) в привычное строковое представление и помещает результат в переданный буфер (buffer). При этом в буфер будет помещено не более digits цифр. Если число может быть представлено таким количеством цифр, то оно будет преобразовано в десятичный (фиксированный) формат, иначе будет выполнено преобразование в экспоненциальный формат, и заданное количество цифр будет содержать мантисса числа. Полученное строковое представление может быть дополнено справа нулями для получения необходимого количества разрядов.
При использовании этой функции необходимо помнить следующее: буфер должен быть достаточно большим, чтобы принять digits цифр, завершающий ноль, а также знак, десятичную точку и экспоненту. Никакого контроля не производится, и граница буфера может быть нарушена. При формировании строки региональные настройки учитываются.
Для вывода чисел с плавающей точкой у функций семейства printf есть следующие тэги типов:
е (или Е) (exponent) — преобразует число в экспоненциальное представление;
f (fixed) — преобразует число в десятичное представление основываясь на дополнительных форматных параметрах (ширина и точность);
g (или G) (general) — преобразует число либо в экспоненциальное, либо в десятичное представление в зависимости от того, какое представление будет короче.
Так же, как и для целых чисел, можно указать дополнительные спецификаторы:
L — передано число в формате long double.
Необходимо заметить, что при передачи переменных типа float производится их продвижение до типа double.
Дополнительно можно указать общее количество значащих цифр в строковом представлении (ширну), а также количество цифр в дробной части (точность) в следующем виде:
% . .
Подробнее об этих форматах можно прочитать в документации по форматной строке функций этого семейства, т. к. подробное описание всех возможностей функций семейства printf выходит за рамки этой статьи.
В C++ числа можно конвертировать в символьное представление с помощью операторов потокового вывода ( UINT SetDlgItemInt(HWND hDlg, intitemId, UINT value, BOOL signed)
UNIT CWnd::GetDlgItemInt(intitemId, UINT value, BOOL signed)

Последним параметров в эти функции передается признак знаковости числа.

Вот наверное и все, что можно сказать про штатные функции преобразования. В следующей части будут рассмотрены различные варианты «самописных» функций преобразования.

А можно оптимизировать и обобщить ф-ии подобные _itow, _ltow, _ultow, _i64tow, _ui64tow и их ANSI аналоги. Причём ниже приведённая ф-ия будет работать куда быстрее чем стандартные. Например, для преобразования целого в строковый параметр UNICODE, все аналоги с префиксом _w, сначала создают буфер char фиксированного размера, затем вызывают одноимённые версии для С-строк, которые вызывают xtoa или x64toa, затем происходит вызов ф-ий преобразования для преобразования ANSI в UNICODE (mbstowcs и __mbstowcs_mt). Эта ф-ии не делает никаких косвенных вызовов, и требует меньше времени на прохождение по её телу. Прюс ещё одно отличие от стандарта, при преобразовании в 16-ричное число к строке добавляется префикс «\0x».

// The following constants must be used during the function call.
enum Radix <
BINARY = 2,
OCTOPLE = 8,
DECIMAL = 10,
HEXADEMICAL = 16
>;

template
void
APIENTRY
itos(Int val, Str buf, UINT size, Radix r=DECIMAL) throw()
<
Str offset = buf; // a pointer to a string
Str first = offset; // a pointer to
// the first digit
UINT delta_y; // the value of a digit
UINT count = 0; // a number of digits
// in the string

// val is negative, so let’s add ‘-‘ to
// the begin of the string.
if (val 0 && size— >= 0) <
delta_y = (Int)(val % r);
val /= r;

if (delta_y > 9)
// The hexademical format.
*offset++ = (delta_y — 10 + ‘a’);
else
// Binary, dicimal and octople formats.
*offset++ = (delta_y + ‘0’);
count++;
>

// Points to the last digit.
*offset— = ‘\0’;

// Now our string corresponds to the integer
// digits but it is in the reverse order. So make
// the backward transformation of it. If it has
// only two characters just swap them without any
// additional actions.
if (count == 1)
return;
else if (count == 2) <
char temp = (char)*offset;
*offset— = *first;
*first++ = temp;
>
// For more than two characters in the string
// reverse full string in the folowing cycle.
else <
delta_y = count / 2;

while (delta_y—) <
char temp = (char)*first;
*first++ = *offset;
*offset— = temp;
>
>
>
>

Использование ф-ии «почти» не отличается от стандартных.

Думаю, таой способ тоже имеет право на жизнь:

template
std::string toString(T val)
<
std::ostringstream oss;
oss
T fromString(const std::string& s)
<
std::istringstream iss(s);
T res;
iss >> res;
return res;
>

// Пример использования
std::string str;
int iVal;
float fVal;

str = toString(iVal);
str = tiString(fVal);

iVal = fromString (str);
fVal = fromString (str);

Дневник программиста

четверг, 23 апреля 2015 г.

C/C++. Преобразование строки в целое число с помощью strtol и strtoll

Дополнение к справочной информации по strtol и strtoll

Программисты C/C++, работающие со стандартными библиотеками, знакомы с использованием функций strtol() и strtoll(), которые можно использовать для преобразования строк в целые числа. Заголовки этих функций доступны в заголовочных файлах stdlib.h или cstdlib (для C++).

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

Однако, в одном из проектов я столкнулся с жесткой рекомендацией использовать именно функции strtol() и strtoll() и это потребовало провести некоторые эксперименты, которые бы дали более полное представление о работе данных функций, кроме того, что было изложено на странице мануала (man 3 strtol).

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

Начать я хочу с того, что эксперименты были проведены на платформе «Ubuntu 14.04 (x64)». Платформа имеет значение по причине того, что стандартные целые типы в C/C++ являются логическими типами и отображаются на разные физические типы в зависимости от используемой платформы. Так, на моей платформе, были получены следующие результаты по интересующим нас логическим целым типам.

Напомним сигнатуру функций strtol() и strtoll().

Таким образом, на моей платформе, различия в использовании функций strtol() и strtoll() нет, что и было подтверждено дальнейшими экспериментами.

Напомним, что для анализа успеха выполненного преобразования нам доступны две величины:

  1. endptr — указатель на символ, на котором преобразование было закончено. Преобразование останавливается на символе, который бы не соответствовал строковому представлению целого числа в указанной системе счисления. Таким образом, для большинства случаев, таким символом должен быть символ конца строки ASCIIZ — ‘\0’. Для отдельных случаев, это могут быть какие-то другие символы. Например, вполне ожидаемым, при совершенно корректной записи литерала, может стать останов на символах ‘\r’, ‘\n’. Вполне реальным был случай обработки строкового значения типа «123\r\n», которая была извлечена из потока в виде строки до символа ‘\n’ и, соответственно, строка «123\r» была передана на преобразование.
  2. errno — глобальная переменная стандартной библиотеки, которая хранит в себе значение последней ошибки. Интересующие нас функции strtol() и strtoll() могут устанавливать эту переменную в значение ERANGE, что соответствует переполнению в большую или меньшую сторону.

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

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

  1. Во-первых, так как указатель на строку преобразования получается из типа std::string, то он всегда корректен и всегда указывает на строку ASCIIZ. Строка может быть пустой или не являться изображением целочисленного литерала, но строка будет ASCIIZ-корректна. Поэтому, нет смысла устраивать соответствующих проверок. В других случаях следует быть уверенным в этом, прежде, чем отдавать строку на преобразование.
  2. Во-вторых, во многом благодаря первой причине, указатель, переданный в функцию strtoll() вторым параметром, всегда будет указывать на какой-то элемент переданной строки ASCIIZ и, также, не требует каких-то проверок своей корректности перед использованием, при анализе результатов функции strtoll().
  3. В-третьих, не следует пренебрегать обнулением глобальной переменной errno. В противном случае, переменная будет хранить результат последней неудачной операции, сбивая с толку анализ последующих успешных операций. Это можно легко проверить запустив функцию test() сначала на строку, где переменная errno получит значение ERANGE, а потом вызвать любое количество раз функцию test() с корректными данными.
value len ptr-s *ptr == ‘\0’ ptr>s LLONG_MIN LLONG_MAX ERANGE
2 63 -2 «9223372036854775806» 19 0xbbb06b-0xbbb058=19 true true false false false
2 63 -1 «9223372036854775807» 19 0xbbb06b-0xbbb058=19 true true false true false
-2 63 «-9223372036854775808» 20 0xbbb06c-0xbbb058=20 true true true false false
2 63 «9223372036854775808» 19 0xbbb06b-0xbbb058=19 true true false true true
-2 63 -1 «-9223372036854775809» 20 0xbbb06c-0xbbb058=20 true true true false true
«xyz» 3 0x1ab6028-0x1ab6028=0 false false false false false
«123xyz» 6 0x232c02b-0x232c028=3 false true false false false

В таблице рассмотрены следующие основные варианты значений.

  1. (2 63 -2): значение внутри диапазона LLONG_MIN..LLONG_MAX: Крайние три правых флага таблицы сброшены.
  2. (2 63 -1) и (-2 63 ): значения на краях диапазона LLONG_MIN..LLONG_MAX — сброшен флаг переполнения, но установлены соответствующие флаги крайних значений.
  3. (2 63 ) и (-2 63 -1): значения за краями диапазона LLONG_MIN..LLONG_MAX — установлен флаг переполнения и установлены соответствующие флаги крайних значений.
  4. «xyz»: строка не являющаяся изображением строкового литерала — последний символ парсинга соответствует началу строки.
  5. «123xyz»: строка начинающаяся изображением строкового литерала, но содержащая недопустимые символы — указатель парсинга сдвинут на три символа и указывает на первый невалидный символ

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

Для большинства случаев, можно предложить следующий вариант проверок.

  1. Разобран как минимум один символ строки.
  2. Изображение целочисленного литерала разобрано до конца (при условии, что он заканчивается на ‘\0’).
  3. Нет переполнения ни в большую ни в меньшую сторону.

Если кроме факта переполнения необходимо контролировать сторону, в которую было сделано переполнение, то вместе с анализом errno необходимо анализировать результат преобразования на соответствие крайнему нижнему (LLONG_MIN) и крайнему верхнему (LLONG_MAX) значениям.

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

Вопрос по c, standards-compliance, standards &#8211 Разница между scanf () и strtol () / strtod () в разборе чисел

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

Я работаю над реализацией стандартной библиотеки C, и меня смущает один конкретный угол стандарта.

Стандарт определяет числовые форматы, принятые scanf семейство функций (% d,% i,% u,% o,% x) в терминах определений для strtol , strtoul , а также strtod .

Стандарт также говорит, что fscanf() вернет во входной поток максимум один символ, и поэтому некоторые последовательности, принятые strtol , strtoul а также strtod неприемлемы для fscanf (ISO / IEC 9899: 1999, сноска 251).

Я попытался найти некоторые значения, которые продемонстрировали бы такие различия. Оказывается, что шестнадцатеричный префикс «0x», за которым следует символ, который не является шестнадцатеричной цифрой, является одним из таких случаев, когда два семейства функций различаются.

Как ни странно, стало очевидно, что ни одна из двух доступных библиотек C, похоже, не согласна с выводом. (См. Тестовую программу и пример вывода в конце этого вопроса.)

То, что я хотел бы услышать,что будет считаться стандартно-совместимым поведением при разборе «0xz»?, Идеально ссылаться на соответствующие части из стандарта, чтобы сделать точку.

scanf() Семейство функций анализирует целые числа так же, как strto*() семейство функций. Например, для спецификатора преобразования x это гласит:

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

Так что если sscanf() а также strtoul() дают разные результаты, реализация libc не соответствует.

Каковы ожидаемые от вас результатыобразец кода должно быть немного неясно, хотя:

strtoul() принимает необязательный префикс 0x или же 0X если base является 16 и спецификация гласит

Субъектная последовательность определяется как самая длинная начальная подпоследовательность входной строки, начиная с первого непробельного символа, который имеет ожидаемую форму.

Для строки «0xz» На мой взгляд, самая длинная начальная подпоследовательность ожидаемой формы «0» поэтому значение должно быть 0 и endptr аргумент должен быть установлен в x .

Mingw-GCC 4.4.0 не согласен и не может проанализировать строку с обоими strtoul() а также sscanf() , Причиной может быть то, что самая длинная начальная подпоследовательность ожидаемой формы «0x» — который не является допустимым целочисленным литералом, поэтому анализ не выполняется.

Я думаю, что это толкование стандарта неверно: подпоследовательность ожидаемой формы всегда должна давать действительное целочисленное значение (если вне диапазона, MIN / MAX значения возвращаются и errno установлен в ERANGE ).

cygwin-gcc 3.4.4 (который использует newlib, насколько я знаю) также не будет анализировать литерал, если strtoul() используется, но анализирует строку в соответствии с моей интерпретацией стандарта с sscanf() .

Помните, что моя интерпретация стандарта склонна к вашей первоначальной проблеме, т.е. что стандарт гарантирует только возможность ungetc() один раз. Чтобы решить, если 0x является частью буквального, вы должны прочитать вперед два символа: x и следующий персонаж. Если это не шестнадцатеричный символ, их нужно отбросить назад. Если есть больше токенов для анализа, вы можете их буферизовать и обойти эту проблему, но если это последний токен, вы должны ungetc() оба персонажа.

Я не совсем уверен, что fscanf() должен делать, если ungetc() выходит из строя. Может быть, просто установить индикатор ошибки потока?

Двуликая локаль в преобразовании из строки в дробное

Каждый разработчик С++ рано или поздно сталкивается с особенностями конвертации дробного числа из строкового представления (std::string) в непосредственно число с плавающей точкой (float), связанными с установленной локалью (locale). Как правило, проблема возникает с различным представлением разделителя целой и дробной частей в десятичной записи числа («,» или «.»).

В данной статье речь пойдет о двойственности локалей С++. Если Вам интересно, почему преобразование одной и той же std::string(«0.1») с помощью std::stof() и std::istringstream во float может привести к различным результатам, прошу под кат.

Проблема

Как и во многих статьях Хабра, все началось с ошибки в коде, фрагмент которого можно свести к следующему:

«Дело в локали», — думаю я, поэтому в отладочных целях перед преобразованием дописываю строку вывода на экран действующего разделителя целой и дробной частей, ожидая увидеть там «,»:

Красивого кода ради стоит отметить, что правильнее было бы добавить проверку существования фасета:

Подробнее про работу с фасетами и локалями в С++ можно узнать здесь: на Хабре, в документации.

Получается, что локаль установлена верная, и строка «0.1» должна преобразовываться корректно. Проверяем преобразование через std::istringstream:

Получаем, что преобразование через std::istringstream работает как ожидается, в то время как std::stof() возвращает неверное значение.

В С++ существуют две глобальных локали:

  • локаль STL, работа с которой возможна через фасеты и класс std::locale (#include );
  • локаль С-библиотеки, работа с которой возможна с помощью функций setlocale() и localeconv() (#include ).

При этом смена глобальной локали с помощью функции std::locale::global() меняет как STL-локаль, так и локаль С-библиотеки, в то время как функция setlocale() влияет только на вторую.

Таким образом, возможно рассогласование:

Загвоздка заключается в том, что функция из C++11 std::stof() (как и std::stod()) базируется на функции strtod() (или wcstod()) из библиотеки С, которая, в свою очередь, ориентируется на локаль С-библиотеки. Получается, что поведение С++ функции опирается на локаль С-библиотеки, а не на локаль STL, как ожидается.

Заключение

Функции C++ STL в своей работе могут использовать функции С-библиотеки, что может приводить к неожиданному результату, в частности, в случае рассогласования глобальных локалей STL и С-библиотеки. Необходимо иметь это в виду.

В моем конкретном случае под *nix был «виноват» класс QCoreApplication библиотеки Qt, который при инициализации вызывает setlocale(), тем самым приводя к возможному рассогласованию описанных локалей.

Как хранятся строки

Эти три массива имеют одинаковую длину и одинаковое содержимое:

Хранятся массивы b1, b2, b3 одинаково — каждый массив хранится единым куском в памяти, эти массивы одинаковой длины.

Но следующие строки хранятся в памяти по-разному:

sizeof(a) равен 6, sizeof(s) равен sizeof(void*) и размеру любого другого адреса, зависит от архитектуры.

Кроме того, строковые константы могут в вашей ОС (например, Linux) хранится в read only области памяти. Т.е. их нельзя изменять, то есть код:

Строку НЕЛЬЗЯ сравнивать ==

Если мы напишем

Массив b содержит такое же слово, на какое указывает переменная p. Но если мы будем сравнивать их ==, то получим ложь. Будет напечатано «НЕ равны», потому что оператор == сравнивает адреса. Получим ложь при сравнении адреса начала массива b и указателя p (разные адреса, p НЕ указывает в начало массива b, он указывает на строковую константу «world»)

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

Как напечатать строку

Печатать строку можно printf по формату %s (string). Печатаются все символы от указанного адреса до ‘\0’. Сам символ ‘\0’ не печатается.

Как прочитать строку

Чтобы прочитать строку, память для нее должна уже быть выделена. Либо объявлен массив подходящей длины, либо выделена динамическая память. В примерах будем объявлять массивы нужной длины.

scanf по формату %s

Формат %s позволяет функции scanf читать набор символов. Выясним на практике, как он работает.

Скомпилируем файл в исполняемый модуль a.out и будем его запускать (вторая строка — что вводим, последняя — что печатает программа):

Оказывается, читается не вся строка, а «слово» до пробельного символа (пробела, табуляции, \n и так далее).

Пробельные символы спереди пропускаются.

Проблема: пользователь может ввести больше 100 символов и мы выйдем за границы массива char a[100]; Что делать? Использовать модификацию к форматеру %s, чтобы указать максимальное количество прочитанных символов.

Так как у нас закончилась печать на букве z, после нее был поставлен символ ‘\0’.

То есть при указанном ограничении в 3 символа записали 4 символа.

Т.е. для массива char a[10] нужно писать scanf(«%9s», a);

Что делать, если нужно прочитать не слово, а строку?

fgets

Строку можно прочитать стандартной функцией gets, но так НЕ НАДО ДЕЛАТЬ!

Даже в help по этой функции пишут, что не нужно ее использовать.

При компиляции мы получаем предупреждение, что не надо использовать gets.

Почему не надо использовать gets? Потому что в функции нигде не указывается, сколько символов можно прочитать, чтобы не выйти за границы массива. Мы никак это не контролируем.

Что делать? Использовать похожую функцию char *fgets(char *s, int size, FILE *stream)

Заметим, что записалось 5 символов ВМЕСТЕ с символом ‘\0’. Т.е. для массива char a[10] можно писать fgets(a, 10, stdin);

Как завершить ввод?

Допустим, мы читаем по словам (или по строкам) текст. Как сказать, что текст закончился?

Чтобы закончить ввод текста с клавиатуры, введите ^D (Linux, Mac) или ^Z (Windows)

Задача (про капитана Флинта)

Капитан Флинт зарыл клад на Острове сокровищ. Он оставил описание, как найти клад. Описание состоит из строк вида: “North 5”, где первое слово – одно из “North”, “South”, “East”, “West”, а второе число – количество шагов, необходимое пройти в этом направлении.

Напишите программу, которая по описанию пути к кладу определяет точные координаты клада, считая, что начало координат находится в начале пути, ось OX направлена на восток, ось OY – на север.

Программа получает на вход последовательность строк указанного вида, завершающуюся строкой со словом “Treasure!”. Программа должна вывести два целых числа: координаты клада.

(Примечание: мы будем признательны, если сможем указать автора задачи. Эта задача столько раз кочевала по разным контестам для школьников, что пора писать слова народные «задача классическая»).

Направление и шаги мы будем читать так:

Теперь нужно узнать — какое именно слово лежит в массиве sdir. Т.е. сравнить строку с образцом.

Стандартные функции языка С

Не забудьте для работы с этими функциями написать

Рассмотрим наиболее используемые функции:

strlen

size_t strlen(const char *s);

Возвращает количество символов в строке БЕЗ подсчета ‘\0’

Попробуем написать такую же функцию mystrlen и проверить ее

Как понять, что возвращать из mystrlen, i, или i-1, или i+1?

Попробуем посчитать в уме длину строки «z». При i=0 учитываем z, i++ сделает i=1, потом проверка s[i]!=’\0′ даст ложь и мы выйдем из цикла. i=1. Вернуть нам надо тоже 1. Т.е return i.

Проверяйте свой алгоритм мысленно на коротких примерах, строках длины 1, 0, максимум 3.

Напишем эту функцию через указатели.

Пусть указатель p сначала указывает на начало строки s, потом в цикле сдвигается на 1 символ p = p+1 или p++, пока его содержимое *p не станет равно ‘\0’ (концу строки).

Как тогда вычислить длину строки? Пусть начало строки «abc» лежит по адресу 100 (s = 100). Тогда буква а лежит по адресу 100, b по адресу 101, c по адресу 102, \0 по адресу 103.

Когда мы закончим цикл, p будет содержать адрес 103 (был бы 102, мы бы цикл продолжали, там буква с). Вернуть нужно число 3. В переменной p у нас число 103, в переменной s число 100. Значит возвращаем p — s.

напоминаем, что тип size_t печатается по формату %zd

Дополнительно: разберите что делает код:

Делает ли эта функция то же самое, или есть ошибка?

strcmp, strncmp — сравнение строк

int strcmp(const char *s1, const char *s2);

int strncmp(const char *s1, const char *s2, size_t n);

Функция strcmp() сравнивает две строки: s1 и s2. Она возвращает целое число, которое меньше, больше нуля или равно ему, если s1 соответственно меньше, больше или равно s2.

Функция strncmp() работает аналогичным образом, но сравнивает только первые n символов строки s1.

Если нужно выяснить, равна строка s образцу, например «Treasure!», то пишем

Так как строки могут быть длинными, то для удобства чтения кода сначала пишут с чем сравниваем результат strcmp.

strcpy, strncpy — копирование строки

char *strcpy(char *dest, const char *src);

char *strncpy(char *dest, const char *src, size_t n);

Функция strcpy() копирует строку, на которую указывает src (включая завершающий символ ‘\0’), в массив, на который указывает dest. Строки не могут перекрываться, и в результирующей строке dest должно быть достаточно места для копии.

Функция strncpy работает аналогично, кроме того, что копируются только первые n байтов строки src. Таким образом, если в n байтах строки src нет нулевого байта, то строка результата не будет заканчиваться символом ‘\0’.

Если длина src меньше, чем n, то остальное место в dest будет заполнено нулями.

Функции strcpy() и strncpy() возвращают указатель на результирующую строку dest.

Попробуем написать mystrcpy сами. Сначала через индексы массива.

Попробуем написать ее через указатели. Указатель s идет по строке src с начала до ‘\0’, сдвигаясь каждый раз на 1 символ. Указатель p идет по строке dest, сдвигаясь каждый раз на 1 символ.

Попробуйте сами разобраться, почему эта функция работает точно так же, как и предыдущая:

strcat, strncat — конкатенация (склейка строк)

char *strcat(char *dest, const char *src);

char *strncat(char *dest, const char *src, size_t n);

Функция strcat() добавляет строку str к строке dest, перезаписывая символ ‘\0’ в конце dest и добавляя к строке символ окончания ‘\0’. Строки не могут перекрываться, а в строке dest должно хватать свободного места для размещения объединенных строк.

Функция strncat() работает аналогичным образом, но добавляет к dest только первые n символов строки src (и дописывает в конец еще и ‘\0’).

Функции strcat() и strncat() возвращают указатель на строку, получившуюся в результате объединения dest.

Можно написать самим функцию mystrcat в 1 строку, используя функции strlen и strcpy.

strchr, strrchr — поиск символа в строке

char *strchr(const char *s, int c);

char *strrchr(const char *s, int c);

Функция strchr() возвращает указатель на местонахождение первого совпадения с символом c в строке s.

Функция strrchr() возвращает указатель на местонахождение последнего совпадения с символом c в строке s.

Функции strchr() и strrchr() возвращают указатель на совпадения с соответствующим символом, а если символ не найден, то возвращают NULL.

strstr — поиск подстроки в строке

char *strstr(const char *str, const char *substr);

Функция strstr() ищет первое вхождение подстроки substr в строке str. Завершающий символ `\0′ не сравнивается.

Возвращает указатель на начало подстроки, или NULL, если подстрока не найдена.

Прочие функции списком

strtok (TODO)

Преобразование из числа в строку — sprintf

Мы умеем печатать часы и минуты в виде 05:12 или 21:07. Как так же быстро переводить часы и минуты в строку по нужному формату?

Используйте функцию sprintf, которая работает почти так же и имеет почти такие же параметры, что и printf, но первым аргументом нужно указать строку, куда будет sprintf писать (она НИЧЕГО не печатает, печатать надо отдельно).

Преобразование из строки в число — scanf

Как вы догадались, аналогичная функция есть и для scanf. Это sscanf

Разберем строку «21:07» в переменные h и m (часы и минуты)

Аналогично можно использовать эту функцию для разбора нецелых чисел. Кроме scanf есть специальные функции, преобразующие строку в число по произвольному базису с контролем ошибок.

strtol, strtod, strtou — преобразование строки в число с контролем ошибок

strtol, strtoll — перевод строки в длинное целое (long int)

strtoul, strtoull — конвертирует строку в беззнаковое целое число (unsigned long integer)

strtod, strtof, strtold — конвертируют строки ASCII в число с плавающей запятой

Прототипы функций:

  • long int strtol(const char *nptr, char **endptr, int base);
  • long long int strtoll(const char *nptr, char **endptr, int base);
  • unsigned long int strtoul(const char *nptr, char **endptr, int base);
  • unsigned long long int strtoull(const char *nptr, char **endptr, int base);
  • double strtod(const char *nptr, char **endptr);
  • float strtof(const char *nptr, char **endptr);
  • long double strtold(const char *nptr, char **endptr);

Функция strtol() конвертирует начальную часть строки nptr в длинное целое в соответствии с указанным base, которое должно находиться в диапазоне от 2-х до 36-х включительно или быть равным нулю.

endptr может быть равным NULL и тогда на него не обращают внимание.

Если endptr указан не NULL, то в него пишут указатель первого некорректного символа из nptr.

Если в строке вообще нет цифр, то strtol() сохраняет начальное значение nptr в *endptr (и возвращает 0). В частности, если *nptr не равно ‘\0’, а **endptr равно ‘\0’ по возвращении, то вся строка состоит из корректных символов.

А кто конвертирует строку в число функциями atoi, atol, atod, тот не контролирует ошибки и злобный еретик.

Функции чтения, использующие динамическую память

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

getline — читаем строку, выделяя память динамически.

Часто бывает, что мы заранее не знаем максимальный размер строки и не можем задать размер массива, чтобы хватило «с запасом». Читать в несколько подходов тоже неудобно.

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

getline() считывает целую строку, сохраняя адрес буфера, содержащего текст, в *lineptr. Буфер завершается null и содержит символ новой строки, если был найден разделитель для новой строки. Если *lineptr равно NULL, то процедура getline() будет создавать буфер для содержимого строки, который затем должен быть высвобожден программой пользователя. Как альтернатива, перед вызовом getline(), *lineptr может содержать указатель на буфер, размещенный через malloc() с размером *n байтов. Если буфер недостаточно велик для размещения всей считанной строки, то getline() изменяет размер буфера с помощью realloc(), обновляя *lineptr и *n при необходимости. В любом случае при успехном вызове *lineptr и *n будут обновлены для отражения адреса буфера и его размера соответственно.

getdelim() работает аналогично getline(), за исключением того, что разделитель строки, отличающийся от символа новой строки будет определен, как аргумент delimiter. Как и с getline(), символ-разделитель не добавляется, если на вводе не появилось знака разделения и уже достигнут конец файла.

При нормальном завершении работы getline() и getdelim() возвращают номер считанных символов, включая символ разделителя, но не включая завершающий символ null. Это значение может использоваться для обработки встроенных символов null при чтении строки. Обе функции возвращают -1 при ошибках чтения строки (включая условие достижения конца файла).

Функция изначально была расширением GNU и была внесена в стандарт POSIX.1-2008.

scanf(«%ms», str)

Аналогично память выделяется динамически при задании форматера чтения %ms. Указанная строка выделяется динамически и ее нужно потом освободить.

C Language Безопасное преобразование строк в число: функции strtoX

пример

С C99 библиотека C имеет набор безопасных функций преобразования, которые интерпретируют строку как число. Их имена имеют форму strtoX , где X является одним из l , ul , d и т. Д., Чтобы определить целевой тип преобразования

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

Если строка фактически не содержит номера, это использование strtod возвращает 0.0 .

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

Этот параметр endptr указывает, было ли успешное преобразование, и если да, то где число закончилось:

Существуют аналогичные функции для преобразования в более широкие целые типы:

Эти функции имеют третий параметр nbase который содержит базу чисел, в которой записано число.

Специальное значение 0 для nbase означает, что строка интерпретируется так же, как литералы чисел интерпретируются в программе на C: префикс 0x соответствует шестнадцатеричному представлению, в противном случае ведущее 0 является восьмеричным, а все остальные числа рассматриваются как десятичные.

Таким образом, наиболее практичным способом интерпретации аргумента командной строки как числа будет

Это означает, что программа может вызываться с параметром в восьмеричном, десятичном или шестнадцатеричном.

Преобразование символьной шестнадцатеричной строки в unsigned int с использованием функции strtoul в C

Я tring для преобразования hex в unsigned int из функции strtoul . Но я получаю вывод как ffffffff . Я использовал библиотеку stdlib.h . Может кто-нибудь сказать мне, в какой части я ошибаюсь?

Функции strtol , strtoll , strtoul и strtoull возвращают преобразованное значение, если оно есть. Если преобразование не может быть выполнено, возвращается ноль. Если правильное значение выходит за пределы диапазона представляемых значений, LONG_MIN , LONG_MAX , LLONG_MIN , LLONG_MAX , ULONG_MAX или ULLONG_MAX (в соответствии с типом возврата и значком значения, если таковые имеются), а значение макроса ERANGE равно хранится в errno .

Попробуйте следующий код:

На моей машине он выйдет

Вы делаете 2 ошибки: значение, возвращаемое strtoul является unsigned long ; и даже тогда ваше значение составляет 128 бит, что больше, чем unsigned long на любой общей платформе.

А также не связывать длину str1 — она должна быть не менее 33 символов; или вместо этого используйте указатель-к-char:

Илон Маск рекомендует:  Локальное хранилище
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL