2

As far as I had understood it, the %hhu format specifier should have the range of an unsigned char. However, in some compilers I test it in, it seems to have the range of an unsigned short instead. Is there a reason for this?

I tried using %hhu to print, for instance, 65535. I would expect this to print 255 on the assumption the value would be cast to an unsigned char. However in CodeBlocks and Tiny C Compiler, I instead get 65535. If I instead try to print 65536, it prints 0, as I would have expected if I had instead used %hu (with one h).

In OnlineGDB, however, I get the behaviour I would have expected.

  • 1
    It's likely a bug in the runtime libraries — the `hh` modifier is a more recent addition to the standard (C99, not C90, IIRC). So it is more likely to be overlooked and/or misimplemented. – Jonathan Leffler Jun 23 '23 at 01:47
  • @entropicdecay, for reference, please report the versions of the errant compilers. – chux - Reinstate Monica Jun 23 '23 at 02:02
  • GCC version 5.1.0 and Tiny C Compiler 0.9.27 – entropicdecay Jun 23 '23 at 02:06
  • 1
    GCC is a compiler only and doesn't include the standard library / runtime, so you can't blame GCC for problems with printf. Rather, find out the version of the standard library you are using (e.g. glibc on Linux systems). Tiny C may be similar, I'm not sure. (That said, why are you using an eight-year-old version of GCC? The latest version is 13.1.) – Nate Eldredge Jun 23 '23 at 02:10
  • If it's using glibc then see this: [Check glibc version for a particular gcc compiler](https://stackoverflow.com/q/9705660/995714). Also [How to check libc version?](https://stackoverflow.com/q/62732447/995714) – phuclv Jun 23 '23 at 02:20
  • It doesn't seem to be using glibc. But I'm not certain. – entropicdecay Jun 23 '23 at 04:11

1 Answers1

1

With *printf(), "%hh":

... Specifies that a following b, d, i, o, u, x, or X conversion specifier applies to a signed char or unsigned char argument (the argument will have been promoted according to the integer promotions, but its value shall be converted to signed char or unsigned char before printing); ... C23dr § 7.23.6.1 7

It is reasonable in suspecting an error when values outside the range of unsigned char are printed.

[Edit]

On-the-other-hand, "hh" is specified to use with a signed char or unsigned char argument. Since OP did not do that, the result is undefined behavior (UB).

If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined. § 7.23.6.1 9

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • 1
    UCHAR_MAX is 255 as it should be... – entropicdecay Jun 23 '23 at 02:07
  • 2
    If the implementation works for any `unsigned char` value passed for `%hhu`, I would say it conforms to the standard, and it does not matter what happens when any other value is passed. The standard says the value is converted from `int` to an `unsigned char`, but that is for an `unsigned char` value converted to `int`. If a program passes some other value for `%hhu`, it has violated the requirement to pass an appropriate argument, before any conversion to `unsigned char` occurs, and the standard does not define the behavior. – Eric Postpischil Jun 23 '23 at 02:22
  • @EricPostpischil Fair point. I'll go with that. – chux - Reinstate Monica Jun 23 '23 at 03:31
  • @EricPostpischil In that case, do the `h` and `hh` length modifiers have any useful purpose, or is their only purpose to allow more UB? – Ian Abbott Jun 23 '23 at 10:50
  • @IanAbbott: The standard is unclear about passing `signed char` (or signed `char`) for `%hhu`; it lumps `signed char` and `unsigned char` together with “or” in a paragraph about “b, d, i, o, u, x, or X” without giving any distinctions about which goes with which. If `signed char` may be used with `%hhu`, then `%hhu` must work with, for example, −1 (producing only “ff”, not “ffffffff”) but is not required to work with −1024 (given an eight-bit `char`). – Eric Postpischil Jun 23 '23 at 11:02