Page 1 of 1

printf semantics

Posted: Tue Dec 27, 2011 3:47 pm
by Kevin
So I need some language lawyers... :)

What is the correct behaviour for the following line of code?

Code: Select all

printf("%.-42d\n", 1337);
The spec says "The precision takes the form of a period (.) followed either by an asterisk * (described later) or by an optional decimal integer" (note that it does not say nonnegative decimal integer as for the field width) and "A negative precision argument is taken as if the precision were omitted."

So I would have expected this format string to be equivalent to "%d", which would mean that the correct output is "1337". However, glibc prints "%.0-42d" and MSVC++ prints "-42d". FreeBSD seems to support my interpretation. Am I missing something and the result is undefined, or are two of the libcs buggy?

Also worth noting that all libcs print the expected 1337 with this code:

Code: Select all

printf("%.*d\n", -42, 1337);

Re: printf semantics

Posted: Tue Dec 27, 2011 6:36 pm
by quok
I don't see how a negative precision would work, so I'm with you (and FreeBSD) on this. However, my printf is VERY bugged and prints "%1337-42d". Now I'm off to fix that.

Re: printf semantics

Posted: Tue Dec 27, 2011 7:29 pm
by Brynet-Inc
OpenBSD's printf(3) calls the precision argument a digit string, and POSIX 1003.1-2008 calls it a decimal digit string.

The words 'digit' and 'string' here make a world of difference, IMHO, implying acceptable values between 0-9.

Still, '-' after '.' should be ignored and the precision be treated as 0, OpenBSD does this.

What specification calls it a decimal integer btw, ISO C?

Re: printf semantics

Posted: Tue Dec 27, 2011 8:08 pm
by gerryg400
In the Posix spec. it says
A negative precision is taken as if the precision were omitted.
I think I misread it the first time and reading it again that is only meant to apply to precision specified with the '*', but my code treats negative or zero precision the same way, however the precision is specified. Therefore I get 1337 in both cases.

If there is any code that relies on the GLIBC interpretation I would be very surprised. I'd say it doesn't matter.

Re: printf semantics

Posted: Wed Dec 28, 2011 3:45 am
by fronty
In my not so humble opinion nothing is said about a negative precision in a conversion specification. The standard says that negative precision argument is ignored, but IMNSHO meaning of a negative precision in a conversion specification isn't discussed.

Re: printf semantics

Posted: Wed Dec 28, 2011 4:14 am
by fronty
berkus wrote:If it is ignored in the argument, it makes sense to ignore it in specification too, otherwise the results will be inconsistent.
Yes, IMO that is the only sensible way to implement those functions, but IMO that case isn't specified in C99.

Just checked current C1X draft, it says that the precision must be a nonnegative decimal integer. Didn't try to find when did they change that.

Re: printf semantics

Posted: Wed Dec 28, 2011 5:22 am
by Kevin
Brynet-Inc wrote:OpenBSD's printf(3) calls the precision argument a digit string, and POSIX 1003.1-2008 calls it a decimal digit string.

The words 'digit' and 'string' here make a world of difference, IMHO, implying acceptable values between 0-9.

What specification calls it a decimal integer btw, ISO C?
Sorry, should have mentioned what I was quoting. It's the C99 spec indeed. You're right, in POSIX it sounds as if negative precision wasn't allowed. But it's an additional restriction that plain C doesn't seem to make (or at least C99, thanks for looking up C1x, fronty!).
Still, '-' after '.' should be ignored and the precision be treated as 0, OpenBSD does this.
No, there's nothing that says that invalid characters should be silently ignored. In this case '-' would be the conversion specifier and we would have undefined behaviour.
gerryg400 wrote:In the Posix spec. it says
A negative precision is taken as if the precision were omitted.
I think I misread it the first time and reading it again that is only meant to apply to precision specified with the '*'
Yes, having another look I think you could (and probably should) read it like that. In which case the spec just wouldn't say anything about negative precision in a format string. Probably another way to make it undefined behaviour.

I guess I should just remove these cases from my tests. In practice nobody will use it anyway, and I'm almost convinced now that it's undefined behaviour.
but my code treats negative or zero precision the same way, however the precision is specified
Zero precision is different from not specifying precision at all: printf("%.d", 0) prints nothing.

Re: printf semantics

Posted: Wed Dec 28, 2011 1:16 pm
by Brynet-Inc
Kevin wrote:
Still, '-' after '.' should be ignored and the precision be treated as 0, OpenBSD does this.
No, there's nothing that says that invalid characters should be silently ignored. In this case '-' would be the conversion specifier and we would have undefined behaviour.
What I meant was, finding '-' after '.' should be ignored along with the precision argument proceeding it, skipping to the conversion specifier.