1

In pure ANSI C (C89), I have the following.

unsigned y=<smallnumber>,x=y+3;
printf("%<whatgoeshere>\n",x-y);

What do I put after the % to be absolutely sure it will print 3? I can see arguments for both %u (result is unsigned if both operands are) and %d (integral expressions are converted to int when passing arguments to printf) here.

Of course both work on any reasonable compiler, which is exactly why I ask here. :-) I have a feeling only one is really correct accordung to standard (but even that could be wrong).

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
Veky
  • 2,646
  • 1
  • 21
  • 30

2 Answers2

5

Unsigned. Use %u. When performing default promotions on integral expressions (because of printf() being a variadic function), unsigned to signed conversion does not happen.

  • Specifically, `unsigned int` is not promoted to `signed int`. `unsigned char` or `unsigned short` will be, but only if their ranges are subranges of `unsigned int`'s range. – Keith Thompson Jun 01 '13 at 22:47
  • @H2CO3 "unsigned to signed conversion does not happen" - Are you sure? Just checked in Visual Studio with `%d` and `x=y-3`. I see `-3` in console – kotlomoy Jun 01 '13 at 23:22
  • @KeithThompson Yes, that's precise. –  Jun 02 '13 at 05:30
  • 1
    @kotlomoy Wrong - you're confusing the behavior of a conversion specifier on a mismatching type (which causes undefined behavior, by the way) with what actually happens. Try `printf("%d\n", (unsigned)-1);` - it will most likely print -1, although you've cast your input to `unsigned`. –  Jun 02 '13 at 05:31
  • @H2CO3 "it will most likely print -1" - this is what I'm talking about. Unsigned `(unsigned)-1` was converted to signed `-1`. I fail to see how there's no conversion here. – kotlomoy Jun 02 '13 at 10:37
  • @kotlomoy There's no conversion and no magic. Whatever the binary representation of the `unsigned` value is, it will be passed to `printf()`. If then it encounters the `%u` conversion specifier, then it will try to interpret that particular bit pattern as an unsigned, if it's given `%d`, then it will try to interpret it as signed. However, theoretically, there is no unsigned -> signed promotion (because that's what the Standard specifies), still this does not tend to be a problem in real-life situations (since almost all architectures nowadays use 2's complement representation for signed –  Jun 02 '13 at 10:41
  • @kotlomoy integers, which acts as you experienced), but it still invokes undefined behavior. [Read this](http://stackoverflow.com/questions/1255775/default-argument-promotions-in-c-function-calls), and don't insist I am wrong when **you** are wrong. –  Jun 02 '13 at 10:41
  • "H2CO3 Apparently I used wrong terminology. Thank you for guidance. But I still fail to see why `%u` is better than `%d` (see my answer) – kotlomoy Jun 02 '13 at 11:22
  • @H2CO3 Just found that Linux uses the same wrong terminology: http://linux.die.net/man/3/printf. Quote:"The conversion specifier - A character that specifies the type of conversion to be applied". What a shame – kotlomoy Jun 07 '13 at 03:33
  • @kotlomoy If you accept a piece of advice: the Open Group's manpages are way better than the linux.die.net ones, and are official :) –  Jun 07 '13 at 04:31
  • @H2CO3 This? http://pubs.opengroup.org/onlinepubs/009695399/functions/printf.html - "Each conversion specification is introduced by the '%' character". – kotlomoy Jun 07 '13 at 15:40
0

This way

printf( "%d\n", (int)(x-y) );

It works for x < y, unlike %u.

Though it doesn't work if result of x-y is out of range of signed int.

kotlomoy
  • 1,420
  • 8
  • 14