最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c - Why is the octal "0" prefix displayed despite the explicit 0 precision when printing 0 integer with # flag

programmeradmin2浏览0评论

Why is the prefix written with octal when using both the # flag and explicit 0 precision for unsigned int conversions? Is it normal?

I've noticed this and it feels like a bug (I'm not claiming it is).

However I'd like to understand how it works because it's making very little sense to me. Is there a rationale behind?

My best guess so far is that the prefix is handled after the precision. Since an empty output (which is what you get with printing 0 with an explicit precision of 0) doesn't start with "0" the "0" prefix is added. But I would've expected the prefix to be included in the concept of "output" and therefore I'd have expected it to not be displayed.


MRE:

/* main.c */
#include <stdio.h>
int main()
{
    printf("%%u conv: [%#.0u]\n", 0);
    printf("%%o conv: [%#.0o]\n", 0);
    return (0);
}

Output:

> gcc -o test main.c && ./test
%u conv: []
%o conv: [0]

Highlights from man 3 printf:

  • On the # flag:

The value should be converted to an "alternate form". For o conversions, the first character of the output string is made zero (by prefixing a 0 if it was not zero already). For x and X conversions, a nonzero result has the string "0x" (or "0X" for X conversions) prepended to it. [...]

  • On the precision:

An optional precision, in the form of a period ('.') followed by an optional decimal digit string. [...] This gives the minimum number of digits to appear for d, i, o, u, x, and X conversions [...].

  • On unsigned integers conversions (u, o, x, X):

[...] The precision, if any, gives the minimum number of digits that must appear; if the converted value requires fewer digits, it is padded on the left with zeros. The default precision is 1. When 0 is printed with an explicit precision 0, the output is empty.

Why is the prefix written with octal when using both the # flag and explicit 0 precision for unsigned int conversions? Is it normal?

I've noticed this and it feels like a bug (I'm not claiming it is).

However I'd like to understand how it works because it's making very little sense to me. Is there a rationale behind?

My best guess so far is that the prefix is handled after the precision. Since an empty output (which is what you get with printing 0 with an explicit precision of 0) doesn't start with "0" the "0" prefix is added. But I would've expected the prefix to be included in the concept of "output" and therefore I'd have expected it to not be displayed.


MRE:

/* main.c */
#include <stdio.h>
int main()
{
    printf("%%u conv: [%#.0u]\n", 0);
    printf("%%o conv: [%#.0o]\n", 0);
    return (0);
}

Output:

> gcc -o test main.c && ./test
%u conv: []
%o conv: [0]

Highlights from man 3 printf:

  • On the # flag:

The value should be converted to an "alternate form". For o conversions, the first character of the output string is made zero (by prefixing a 0 if it was not zero already). For x and X conversions, a nonzero result has the string "0x" (or "0X" for X conversions) prepended to it. [...]

  • On the precision:

An optional precision, in the form of a period ('.') followed by an optional decimal digit string. [...] This gives the minimum number of digits to appear for d, i, o, u, x, and X conversions [...].

  • On unsigned integers conversions (u, o, x, X):

[...] The precision, if any, gives the minimum number of digits that must appear; if the converted value requires fewer digits, it is padded on the left with zeros. The default precision is 1. When 0 is printed with an explicit precision 0, the output is empty.

Share Improve this question edited Mar 20 at 2:19 vmonteco asked Mar 19 at 13:19 vmontecovmonteco 15.6k17 gold badges59 silver badges91 bronze badges 2
  • 1 Furthermore: d i o u x X conversions print 0 as [] [] [0] [] [] [] and 1 as [1] [1] [01] [1] [0x1] [0x1] (explicitly: [%#.0d] [%#.0i] [%#.0o] [%#.0u] [%#.0x] [%#.0X]) – Wyck Commented Mar 19 at 13:39
  • 1 You can see comments explaining it on this line – Wyck Commented Mar 19 at 14:03
Add a comment  | 

2 Answers 2

Reset to default 5

This is normal, and specified by the C standard:

#
The result is converted to an ''alternative form''. For o conversion, it increases the precision, if and only if necessary, to force the first digit of the result to be a zero (if the value and precision are both 0, a single 0 is printed). For x (or X) conversion, a nonzero result has 0x (or 0X) prefixed to it. ...

For o conversion, # forces a leading zero even if the value and precision are both 0. For x conversion, the leading 0x or 0X is only prefixed to nonzero values.

You can also see that the man page you quoted says something similar: # with o forces a leading zero no matter what, while # with x or X only adds a prefix to nonzero values.

Note that o, x, and X are the only integer conversions for which the behavior of # is defined. Using # with u is undefined behavior.

It behaves as specified by ISO C23 7.23.6.2:

  • # The result is converted to an "alternative form". For o conversion, it increases the precision, if and only if necessary, to force the first digit of the result to be a zero (if the value and precision are both 0, a single 0 is printed).

Furthermore, # together with %d or %u is not specified, so %#.0u is either undefined behavior or a non-standard extension.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论