Запутанный язык в спецификации strtol, et al - PullRequest
6 голосов
/ 15 июля 2011

Спецификация для strtol концептуально делит входную строку на «начальный пробел», «предметную последовательность» и «конечную строку» и определяет «предметную последовательность» как:

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

Когда-то я думал, что бизнес "самая длинная начальная подпоследовательность" сродни тому, как работает scanf, где "0x@" будет сканировать как "0x", неудачное совпадение, а затем "@" как следующий непрочитанный символ , Однако после некоторого обсуждения я в основном убежден, что strtol обрабатывает самую длинную начальную подпоследовательность ожидаемой формы, а не самую длинную начальную строку, которая является начальной подпоследовательностью некоторой возможной строки ожидаемой формы.

Что меня все еще смущает, так это язык в спецификации:

Если подчиненная последовательность пуста или не имеет ожидаемой формы, преобразование не выполняется; значение str хранится в объекте, на который указывает endptr, при условии, что endptr не является нулевым указателем.

Если мы примем то, что кажется правильным определением «предметной последовательности», не существует такой вещи, как непустая предметная последовательность, которая не имеет ожидаемой формы, и вместо этого (чтобы избежать избыточности и путаницы) текст следует просто прочитать:

Если предметная последовательность пуста, преобразование не выполняется; значение str хранится в объекте, на который указывает endptr, при условии, что endptr не является нулевым указателем.

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

Ответы [ 4 ]

3 голосов
/ 15 июля 2011

Я думаю, что язык C99 вполне понятен:

Предметная последовательность определяется как самая длинная начальная подпоследовательность строка ввода, начинающаяся с первого символа, не являющегося пробелом, это в ожидаемой форме.

Учитывая "0x@", "0x@" не имеет ожидаемой формы; "0x" не имеет ожидаемой формы; следовательно, "0" - самая длинная начальная подпоследовательность ожидаемой формы.

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

В другом языке, кроме "C", дополнительный предмет для конкретного языка Формы последовательности могут быть приняты.

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

Кажется, что формулировка в последнем абзаце просто "пояс и скобки".

2 голосов
/ 15 июля 2011

Может быть легче понять, если вы начали с §7.20.1.4 (функции strtol, strtoll, strtoul и strtoull) ¶2 стандарта C99 вместо ¶4:

Functions2 Функции strtol, strtoll, strtoul и strtoull преобразуют начальную часть строки, на которую указывает nptr, в представление long int, long long int, unsigned long int и unsigned long long int соответственно.Во-первых, они разбивают входную строку на три части: начальную, возможно, пустую, последовательность символов пробела (как определено функцией isspace), последовательность субъекта, напоминающую целое число, представленное в некотором основании, определяемом значением base, ипоследняя строка из одного или нескольких нераспознанных символов, включая завершающий нулевой символ входной строки.Затем они пытаются преобразовать предметную последовательность в целое число и вернуть результат.

¶3 Если значение base равно нулю, ожидаемая форма предметной последовательности представляет собой целочисленную константу, как описано в6.4.4.1, необязательно с предшествующим знаком плюс или минус, но не включая целочисленный суффикс.Если значение base находится между 2 и 36 (включительно), ожидаемая форма предметной последовательности представляет собой последовательность букв и цифр, представляющих целое число с основанием, заданным base, необязательно с предшествующим знаком плюс или минус, но не включаяцелочисленный суффикс.Буквы от (или A) до z (или Z) имеют значения от 10 до 35;разрешены только буквы и цифры, приписанные значения которых меньше базовых.Если значение base равно 16, символы 0x или 0X могут необязательно предшествовать последовательности букв и цифр, следуя за знаком, если они присутствуют.

¶4 Тематическая последовательность определяется как самая длинная начальная подпоследовательность вводастрока, ...

В частности, ¶3 разъясняет, что такое последовательность субъекта.

1 голос
/ 15 июля 2011

Я полностью согласен с вашей оценкой: по определению все непустые предметные последовательности имеют ожидаемую форму, поэтому формулировка стандарта сомнительна.

В случае функций преобразования с плавающей запятой есть еще одна ошибка (C99: TC3 раздел 7.20.1.3, §3):

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

Это означает, что вся входная строка должна иметь ожидаемую форму, что противоречит назначению параметра endptr. Можно утверждать, что ожидаемая форма для входной строки отличается от ожидаемой формы для предметной последовательности, но это все еще довольно запутанно.

Вы также правы в том, что семантика семейства функций strto*() и *scanf() различна: если оба они совпадают, они всегда будут согласовывать значение и использовать одинаковое количество символов (и любую реализацию libc, где они do не сломан, включая newlib и glibc в прошлый раз, когда я проверял), но *scanf() дополнительно не соответствует тем случаям, когда необходимо вернуть более одного символа, как в ваших примерах "0x@" и "1.0e+".

1 голос
/ 15 июля 2011

Спецификация POSIX для strtol кажется более понятной:

Эти функции должны преобразовывать начальную часть строки, на которую указывает str, в тип long и long longпредставление соответственно.Сначала они разбивают входную строку на три части:

  1. Исходная, возможно, пустая, последовательность символов пробела (как указано в isspace ())

  2. Субъектная последовательность, интерпретируемая как целое число, представленное в некотором основании, определяемом значением base

  3. Конечная строка из одного или нескольких нераспознанных символов, включая завершающий символ NULвходная строка.

Затем они должны попытаться преобразовать последовательность объекта в целое число и вернуть результат.

Но, конечно, это не такнорматив и "соответствует стандарту ISO C".

...