В моих экспериментах это выражение
double d = strtod("3ex", &end);
инициализирует d
с помощью 3.0
и помещает end
указатель на символ 'e'
во входную строку. Это точно так, как я ожидаю, что он будет себя вести. Символ 'e'
может выглядеть как начало части экспоненты, но поскольку фактическое значение экспоненты (требуемое в соответствии с 6.4.4.2) отсутствует, то 'e'
следует рассматривать как полностью независимый символ.
Однако, когда я делаю
double d;
char c;
sscanf("3ex", "%lf%c", &d, &c);
Я заметил, что sscanf
потребляет как '3'
, так и 'e'
для спецификатора формата %lf
. Переменная d
получает значение 3.0
. Переменная c
заканчивается 'x'
. Это выглядит странно для меня по двум причинам.
Во-первых, поскольку спецификация языка относится к strtod
при описании поведения спецификатора формата %f
, я интуитивно ожидал, что %lf
будет обрабатывать вход таким же образом strtod
(т.е. выбрать ту же позицию, что и точка окончания). Тем не менее, я знаю, что исторически scanf
должен был возвращать не более одного символа обратно во входной поток. Это ограничивает расстояние любого внешнего вида scanf
может выполняться одним символом. И в приведенном выше примере требуется, по крайней мере, два символа вперед. Итак, допустим, я согласен с тем, что %lf
потреблял как '3'
, так и 'e'
из входного потока.
Но тогда мы сталкиваемся со второй проблемой. Теперь sscanf
должен преобразовать этот "3e"
в тип double
. "3e"
не является допустимым представлением константы с плавающей запятой (опять же, согласно 6.4.4.2 значение экспоненты не является необязательным). Я ожидал бы, что sscanf
будет считать этот ввод ошибочным: завершайте при преобразовании %lf
, возвращайте 0
и не оставляйте d
и c
неизмененными. Однако выше sscanf
завершается успешно (возврат 2
).
Такое поведение согласовано между реализациями GCC и MSVC стандартной библиотеки.
Итак, мой вопрос в том, где именно в стандартном документе на языке C он позволяет sscanf
вести себя так, как описано выше, ссылаясь на вышеуказанные две точки: потребление более чем strtod
делает и успешно конвертирует такие последовательности как "3e"
?
Изучая результаты моего эксперимента, я могу, вероятно, "перестроить" поведение sscanf
: потреблять столько, сколько "выглядит правильно", никогда не отступать, а затем просто передавать потребляемую последовательность на strtod
. Таким образом, 'e'
потребляется %lf
, а затем просто игнорируется strtod
. Но были ли все это в спецификации языка?