Fix printf conversion of a zero value with a precision of zero - #4942
Open
sachhg wants to merge 1 commit into
Open
Fix printf conversion of a zero value with a precision of zero#4942sachhg wants to merge 1 commit into
sachhg wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
C requires that converting a zero value with a precision of zero produces no characters (C99 7.21.6.1p8, "The result of converting a zero value with a precision of zero is no characters").
fmt::printfprints0instead. This affectsd,i,o,u,xandX.Reproduction
printffmt::sprintf%.0d0%.d0%.0x0%5.0d␣␣␣␣␣␣␣␣␣0%-5.0d␣␣␣␣␣0␣␣␣␣%+.0d++0% .0d␣␣0%#.0x0Found by diffing
fmt::sprintfagainstsnprintfacross the flag, width and precision combinations fordiouxXfFeEgG. A nonzero value, or any precision above zero, was already correct.Changes
write_intnow emits no digits when the precision is zero and the value is zero. The prefix, the sign and the width padding are unaffected, which is what C requires:%+.0dstill yields+and%5.0dstill yields five spaces.%#ois the one exception in C: "if the value and precision are both 0, a single 0 is printed".printf.hclearsaltfor a zero value before the conversion specifier has been parsed, so it now remembers that case and raises the precision to 1 for octal. That mirrors how the standard states the rule, as#increasing the precision when necessary to force a leading zero.This is scoped to
printfby construction. The format API rejects a precision for integer arguments (fmt::format("{:.0}", 0)throwsinvalid format specifier), sowrite_intcan only see a nonnegative precision throughprintf.Testing
Added
printf_test.zero_int_with_zero_precision, covering every affected conversion, the#oand#xcases, the sign, space and width interactions, and unaffected cases such as%.0dwith 42 and%.1dwith 0. Every expected value in it was generated from the platformsnprintfrather than written by hand.EXPECT_PRINTFalso exercises the positional form of each.The test fails on main, producing
0where the empty string is required. All 22 ctest targets pass with the change.Not included
The same sweep showed that
fmt::printfapplies the+and space flags to the unsigned conversionso,u,xandX, where C ignores them, so%+xof 0 gives+0rather than0. C calls those flags undefined for conversions other than signed ones, so it is a compatibility difference rather than a conformance bug, and it seemed better kept out of this change. Happy to open a separate PR if you would like it matched to the common implementations.