printf semantics

Programming, for all ages and all languages.
Post Reply
Kevin
Member
Member
Posts: 1071
Joined: Sun Feb 01, 2009 6:11 am
Location: Germany
Contact:

printf semantics

Post 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);
Developer of tyndur - community OS of Lowlevel (German)
quok
Member
Member
Posts: 490
Joined: Wed Oct 18, 2006 10:43 pm
Location: Kansas City, KS, USA

Re: printf semantics

Post 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.
User avatar
Brynet-Inc
Member
Member
Posts: 2426
Joined: Tue Oct 17, 2006 9:29 pm
Libera.chat IRC: brynet
Location: Canada
Contact:

Re: printf semantics

Post 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?
Image
Twitter: @canadianbryan. Award by smcerm, I stole it. Original was larger.
gerryg400
Member
Member
Posts: 1801
Joined: Thu Mar 25, 2010 11:26 pm
Location: Melbourne, Australia

Re: printf semantics

Post 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.
If a trainstation is where trains stop, what is a workstation ?
fronty
Member
Member
Posts: 188
Joined: Mon Jan 14, 2008 5:53 am
Location: Helsinki

Re: printf semantics

Post 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.
fronty
Member
Member
Posts: 188
Joined: Mon Jan 14, 2008 5:53 am
Location: Helsinki

Re: printf semantics

Post 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.
Kevin
Member
Member
Posts: 1071
Joined: Sun Feb 01, 2009 6:11 am
Location: Germany
Contact:

Re: printf semantics

Post 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.
Developer of tyndur - community OS of Lowlevel (German)
User avatar
Brynet-Inc
Member
Member
Posts: 2426
Joined: Tue Oct 17, 2006 9:29 pm
Libera.chat IRC: brynet
Location: Canada
Contact:

Re: printf semantics

Post 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.
Image
Twitter: @canadianbryan. Award by smcerm, I stole it. Original was larger.
Post Reply