В моих экспериментах это выражение
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. Но были ли все это в спецификации языка?