Рассмотрим следующий вызов printf()
:
printf("%.-1f", 34.14);
он задает отрицательное значение точности -1. Выполняя этот вызов с помощью glibc, мы получаем:
%0.-1f
это верно? Если да, то почему?
@EricPostpischil: Справедливое замечание. Я ошибочно предположил, что любые изменения в printf будут только «аддитивными», т. е. новым допустимым синтаксисом, а не «отрицательными», т. е. делающими действительный синтаксис недействительным.
Я считаю, что это ошибка. стандарт C (ISO/IEC 9899:1999) гласит:
§7.19.6.1
Каждая спецификация преобразования обозначается символом %. После % последовательно появляются следующие символы:
... отрезок...
- Необязательная точность... Точность принимает форму точки (.), за которой следует либо звездочка * (описанная ниже), либо необязательное десятичное целое число;
... отрезок...
- Как отмечалось выше, ширина поля или точность, или и то, и другое, могут быть обозначены звездочкой. В этом случае аргумент int предоставляет ширину или точность поля. ... Аргумент отрицательной точности принимается так, как если бы точность была опущена.
Ну, -1 — отрицательное целое число; поэтому его можно законно указать буквально в строке формата; и хотя текст, объясняющий, что делать с отрицательной заданной точностью, появляется в пункте, касающемся значений, обозначенных звездочкой, конечно, это должна быть та же логика, что и для значений, указанных буквально (точно так же, как и для ширины).
Итак, я считаю, что в этой причине значение точности следует игнорировать, а строка формата эквивалентна "%f"
, поэтому вывод должен быть:
34.140000
(точность по умолчанию 6)
Целочисленный аргумент точности в 5 не является частью строки, а является аргументом функции printf, например: printf("%.*f", -1, 34.14)
@OfNothing: Действительно, но в пункте 5 указано, как интерпретировать отрицательное значение точности.
Формулировка изменилась между C11 и C17/18. В C17/18 говорится:
§7.21.6.1 Функция
fprintf
4. [...] Точность принимает форму точки (.
), за которой следует либо звездочка*
(описано позже), либо необязательное неотрицательное десятичное целое число; [...]
Насколько я прочитал, поведение при использовании отрицательного целого числа не определено.
Это не критическое изменение, поскольку оно не делает ранее действительные программы недействительными. Намерение никогда не заключалось в том, чтобы допускать отрицательные значения, как указано в DR220 - Определение «десятичного целого числа» / N32079:
Термин «десятичное целое число» не определен ни в Стандарте, ни в ISO 2382-1. Поэтому невозможно сказать, являются ли в каждом случае:
- значение может быть нулевым
- можно использовать незначащую начальную нулевую цифру
- значение может быть отрицательным.
Предлагаемое техническое исправление
Добавьте новый абзац в 7.1.1:
[#x] Десятичное целое число — это последовательность цифр, которая может начинаться с одного или нескольких нулей, но тем не менее интерпретируется как десятичная, а не восьмеричная.
Техническое исправление
В 7.19.6.1P4, который частично гласит: «[...] или необязательное десятичное целое [...]»
измените «десятичное целое число» на «неотрицательное десятичное целое число».
Это хороший ответ, но он дополняет обсуждение C99. И если я скомпилирую с -std=c99, я все равно получу тот же результат от glibc.
@einpoklum Вчера вечером я потратил некоторое время на поиск статьи, в которой было предложено это изменение слова, чтобы иметь возможность предоставить первоначальную мотивацию для него, но я не смог найти такую статью. Я предполагаю, что это было сделано потому, что кто-то мог прийти к выводу, что вы пришли, но у него никогда не было определенного поведения. Ни одна из основных реализаций не рассматривает его как 0
в режиме до C17/18, что подтверждает мое предположение. Однако я не хотел включать это предположение в ответ.
@einpoklum Наконец-то я нашел это. В отчете о дефекте вместо «неотрицательного» использовалось «неотрицательный», поэтому я его сначала не нашел :-)
Я думаю, что «неотрицательное десятичное целое число» по-прежнему является ошибкой в стандарте, потому что, неявно признав, что десятичное целое число может иметь знак минус, оно также допускает, что может быть знак плюс, но я не думаю, что это было предназначено для того, чтобы разрешить и определите printf("%.+1f\n", 34.14);
. Вероятно, следовало бы сказать «десятичное целое число без знака» или «непустая последовательность цифр».
@EricPostpischil У меня была похожая мысль, когда я нашел отчет о дефекте. Глядя на первое предложенное исправление: «Десятичное целое число — это последовательность цифр, которая может начинаться с одного или нескольких нулей, но, тем не менее, интерпретируется как десятичная, а не восьмеричная» — для отрицательных чисел вообще нет места — но они все же нашли это. необходимо сделать это явным.
Вы отметили этого юриста по языку, но не указали версию C в вопросе и ответили цитатой из C 1999. В документации для тега C сказано, что используется последняя версия стандарта C, в настоящее время 9899:2018, если иное не указано в вопросе. Отмечая языкового юриста, вы должны точно указать, о какой версии языка вы спрашиваете. Формулировка этого правила менялась в период с 1999 по 2018 год.