LINUX.ORG.RU

Чем парсить целые числа?

 , ,


0

3

Ситуация такова, что даже хваленый boost::lexical_cast может удивить: https://wandbox.org/permlink/PP0RTfmifVO816U0

std::cout << boost::lexical_cast<unsigned int>("-1"); // исключения не будет

Спойлер: http://www.boost.org/doc/libs/1_60_0/doc/html/boost_lexical_cast/frequently_a...

Скажите, есть ли вообще в природе средства для парсинга целых чисел (пускай даже ограниченные до radix=10) которые не удивляют?

Т.е. :

  • Не пропускают пробелов вначале строки
  • Интерпретируют всю строчку (а не до первого непонятного символа)
  • Нет автоматического определения radix (т.е. "012" будет 12 а не 10)
  • Могут интерпретировать подстроку (но польностью). Как boost::lexical_cast(str, len)
  • Трактуют 8-ми битные типы как числа (а не как символ/байт, ибо первый байт строки я и сам могу взять)
  • ... не имеют других подводных камней
★★★★★

Последнее исправление: KennyMinigun (всего исправлений: 1)

Ответ на: комментарий от pftBest

Ааа, вот что значит обзывать foo то, что совершенно ясно, что оно типа check_overflow() :)

Собственно я всегда и сравнивал unsigned, с > MAX(_SIGNED_)INT, можно, конечно, и смену знака сравнивать, но тогда две функции надо делать для предотвращения оптимизации и гарантировать передачу значения с предварительно известным знаком.

Собственно я не совсем понимаю, чего тут все изобретают strtol()... Казалось бы, и overflow там проверяется и окончание можно проверить на нужное.

vodz ★★★★★
()
Ответ на: комментарий от vodz

при увеличении числа на !=0 значение, переполнение детектируется тупым сравнением, что результат не стал больше?

Как уже писали выше: переполнение знакового — это UB. А UB — это ни-ни. Ибо бесценные часы совокупления с дебагером под разными углами обзора — то еще удовольствие (особенно когда Ънтерпрайз бинарник в пару гигов и древний gdb, или того хуже — Солярка и dbx).

KennyMinigun ★★★★★
() автор топика
Ответ на: комментарий от RazrFalcon

strtol минное поле.

Это только бла-бла. Нормальная такая функция, со всеми проверками.

vodz ★★★★★
()
Ответ на: комментарий от KennyMinigun

Как уже писали выше: переполнение знакового — это UB. А UB — это ни-ни

UB там идёт от UB реализации в самой архитектуре — не известно, как любая архитектура среагирует на переполнение: то ли будет недопустимая операция, то ли будет сложение то ли нет, то ли будет отрицательное значение, то ли вообще неизвестно что. Для конкретной архитектуры та же strtol() вполне справляется с переполнением: сравнивается с безнаковым и MAX_INT, запоминая знак и работая предварительно с положительным значением.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

Как же вы надоели с вашими архитектурами. Еще раз повторю, UB не в архитектуре, UB в языке и компиляторе.

Если у тебя в программе UB, то компилятор
неправильно соптимизирует твой код. И всякие хаки вроде

две функции надо делать для предотвращения оптимизации

не помогут как ни крути. Если есть UB, то проблемы будут по любому, даже на «хорошей» архитектуре вроде x86.

pftBest ★★★★
()
Ответ на: комментарий от pftBest

Как же вы надоели с вашими архитектурами.

Как же вы надоели с вашими «минными полями» и тому подобным бла-бла с изобретением собственных велосипедных strtol(). Не хотите запостить баг, что strtol не может детектировать и выставлять errno=ERANGE? Они же не правы, правда?

vodz ★★★★★
()
Ответ на: комментарий от vodz

Я не говорил ничего про strtol. Я говорил про ручные проверки которые обречены на провал. strtol может и правильно работает, но он не подходит под критерии автора темы, так что какой смысл его обсуждать?

pftBest ★★★★
()
Ответ на: комментарий от pftBest

но он не подходит под критерии автора темы

Он(а) удовлетворяет всем кроме «хочу чтобы первые пробелы были ошибочны» и загадочное «всю строку». Оба эти критерия специально оставлены на усмотрения пользователя и решаются без правки библиотечной функции, ибо уж чего-чего, а «вся строка» может быть разной для каждого применения. Например, если встретится точка, то это тоже валидная строка, только тип не int, а плавающая арифметика/IP адрес, или прочий валидный разделитель типа '/'...

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

и загадочное «всю строку».

Обьясняю на пальцах:

"123qwe" (length = 6) -> должна быть ошибка
"1234456" (length = 3) -> должно распарсить только 123
"1234aa" (length = 3) -> снова 123
"   123" (length <= 6) -> ошибка (length не существенно)

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

Например, если встретится точка, то это тоже валидная строка, только тип не int, а плавающая арифметика/IP адрес, или прочий валидный разделитель типа '/'...

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

P.S. Подчеркну, что strtol может «улететь» за границы куска памяти, если продолжение удовлетворяет std::isdigit(str[i]) с не-нуль терминированными строками это уже может быть опасно.

P.P.S. А strtoul (из за спецификации С99) считает, что "-123" — это норма (ц).

KennyMinigun ★★★★★
() автор топика
Последнее исправление: KennyMinigun (всего исправлений: 1)
Ответ на: комментарий от KennyMinigun

«123k» (length = 6) -> должна быть ошибка

Сегодня для вас k - ошибка, а завтра - валидный суффикс «кило» (ну вот так заказчику вдруг понадобилось). Потому делать узкоспециализированную функцию просто глупо. Интерфейс то вам оставлен - проверяйте endptr

«1234456» (length = 3) -> должно распарсить только 123

Это уже совсем-совсем узкоспециальное. Заведите буфер length+1, копируйте, добавляйте 0 и проверяйте из него. Оно только на первый взгляд будет медленнее, но на самом деле проверять по каждому символу, что не кончился ли length будет медленнее, чем копировать в буфер.

«1234aa» (length = 3) -> снова 123

Это везде по умолчанию.

" 123" (length <= 6) -> ошибка (length не существенно)

А если '$' будет вместо пробелов - не ошибка? ;) Ктож вам запрещает проверить первый символ на предмет ошибочных/неошибочных?

vodz ★★★★★
()
Ответ на: комментарий от vodz

Это превращается в какой-то флейм (по кругу). Как я сказал — хочу простую функцию без сюрпризов. Городить для этого код вокруг strtol/*scanf/atol сложнее чем написать самому (что я уже и сделал).

KennyMinigun ★★★★★
() автор топика
Ответ на: комментарий от vodz

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

pftBest ★★★★
()
Ответ на: комментарий от pftBest

А ты предлагаешь вручную их написать.

Дык, ясен пень, любые спец хотелки должны быть либо написаны автором, либо в job. А я вообще-то спросил, чем не устраивает strtol() и простейшие обёртки под конкретные хотелки, ибо все предложенные варианты велосипеды ещё те.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.