1
#include <stdio.h>
#include <string.h>

main()
{
short int x=0x55AA;
printf("%x ",~x);
}

Above program gives output : ffffaa55. I was expecting o/p only aa55 as short int is 2 bytes. Can anyone please explain it?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
debonair
  • 2,505
  • 4
  • 33
  • 73

4 Answers4

5

You have:

short int x = 0x55AA;
~x;

The expression ~x has the type int.

Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
  • ... Additionally "%x" is an int format specifier in any case. – Clifford Aug 30 '14 at 17:35
  • 1
    @Clifford: More precisely, a narrow variadic argument will be promoted to `int` regardless of what format specifier is used. (And `%x` is a actually an `unsigned int` format specifier) – AnT stands with Russia Aug 30 '14 at 17:37
  • @AndreyT : Precisely ;-) – Clifford Aug 30 '14 at 17:43
  • if every data type needs to be converted to int then what about char x=0X55AA; printf("%x",~x); ? – debonair Aug 30 '14 at 19:24
  • That's slightly more complicated because it's an implementation choice if `char` is signed or unsigned. So, depending on your implementation, `~x` is promoted to either a `signed int` or an `unsigned int`. – Bill Lynch Aug 30 '14 at 19:25
  • @sharth Question "`char` ... is promoted to either a `signed int` or an `unsigned int`". "If an `int` can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions" C11dr §6.3.1.1 2. This implies to me that an 8-bit `char`, `signed/unsigned` or neither would be promoted to an `int`, not `unsigned`. – chux - Reinstate Monica Aug 31 '14 at 04:13
  • 1
    @sharth: If `char` is narrower than `int`, `char` is always promoted to signed `int`, regardless of whether `char` itself is signed or unsigned. – AnT stands with Russia Aug 31 '14 at 05:51
5

C language never performs calculations in types narrower than [signed/unsigned] int. Every time you use a value of narrower type (like short or char) in an expression, that value is implicitly promoted to [signed/unsigned] int. One important detail here is that even if the original narrow type is unsigned it will still be promoted to a signed type int (assuming it fits into the range of int). This is something that should be kept in mind in cases like that.

Note that it is not just the expression ~x that has type int, it is the x itself that is promoted to int even before the ~ has a chance to do anything. In other words, your ~x is interpreted as ~(int) x.

If you need a result of the original narrow type, you have to convert it back to the original type explicitly. In case of printf, where explicit conversion won't solve anything (since variadic argument will be converted to int anyway), you can use printf format specifiers to interpret the corresponding argument a value of narrower type.

As a side note, %x format specifier expects an argument of unsigned int type. Passing negative int value instead is not allowed.

Also, it is always a better idea to use unsigned types for any operations with bit-level semantics.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 2
    Even if you cast the `~x` back to `short int`, it will be promoted to `int` again when passed to `printf`. At that point, it will likely be sign-extended (because the msb is now set). To get the desired behavior, it should be cast to `unsigned short`, or you should use the correct format specifier. – pat Aug 30 '14 at 17:28
  • if every data type needs to be converted to int then what about char x=0X55AA; printf("%x",~x); ? – debonair Aug 30 '14 at 19:25
  • @debonair: What about it? As I said above, in `~x` values of `char` type get converted to `int` in exactly the same way. The only problem is that `0x55AA` will not fit into a typical `char`. – AnT stands with Russia Aug 30 '14 at 19:31
1
main()
{
 short int x=0x55AA;
 printf("%x ",~x);
}

Here,~x is treated as signed int.If you want o/p as aa55,then you should do typecast to unsigned short in.so,Try like this..

 main()
 {
   short int x=0x55AA;
   printf("%x ",(unsigned short int)~x);//typecasting
 }
Anbu.Sankar
  • 1,326
  • 8
  • 15
0

For the most part arithmetic and logic operators are defined for int and long, an expression involving smaller types involves an implicit conversion and the result will be the larger type.

Moreover "%x" is an unsigned int format specifier in any case.

There are various solutions, e.g.:

short x = 0x55AA ;
short nx = ~x ;
printf("%x ",~nx) ;


short x = 0x55AA ;
printf("%x ",~x & 0x0000FFFF ) ;
Clifford
  • 88,407
  • 13
  • 85
  • 165