Kiran HS
Kiran HS

Reputation: 27

What is the use of unsigned char in bitwise negation operation?

unsigned char a = 10,b;
b = ~a;
printf(" %d \n ",b);

output:

245

same program if I use int instead of unsigned char the o/p changes to -11

Upvotes: 1

Views: 1480

Answers (5)

Eswaran Pandi
Eswaran Pandi

Reputation: 670

In C, int and char has to types

  1. Signed
  2. Unsigned

If user gives int [16 bits] or char [8 bits], then compiler takes by default as signed. for unsigned, Users need to mention explicitly.

unsigned char ranges from 0 to 255 [8 bits].

signed char ranges from -128 to 0 to 127 [8 bits].

As per your program,

Case 1:

a is unsigned char, the output 245 is with in the range of 0 to 255. so you got output as 245.

    0, 1, 2, 3, 4, ..................... 254, 255
    |                                          |
    |<- <- <- <- <- <- <- <- <- <- <- <- <- <- |  

    example:
          unsigned char a = 257;       // more than 255.
          printf("a = %d", a);          

         **Output** : a = 1.        // [ 0,1,...255,0 [256th], **1** [257th]

         unsigned char a = 129;       // with in range of 255.
          printf("a = %d", a);          

         **Output** : a = 129.                   

Case 2:

a is signed char, the same output 245 is starting from 0 to 127 and then starts from -128, -127, -126, ..... -11 (245th Position) and prints -11.

 -128, -127, -126, ..... -11, -10, .. -1, 0, 1, 2, 3, .....126, 127
   |                                                             |       
   |<- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <- <-<-|

 example:
          char a = 257;          // more than 255.
          printf("a = %d", a);          

         **Output** : a = 1.     // [ 0,1,...127,-128,-127,....-1, 0 [256th], **1** [257th].

          char a = 129;              // with in range of 255.
          printf("a = %d", a);          

         **Output** : a = -127.      // [ 0,1,...127,-128 [128th], **-127** [129th].             

The same case is applicable for int data type also.

Upvotes: 0

Jonathan Leffler
Jonathan Leffler

Reputation: 753990

The variable a contains the unsigned char value 10. Assuming an orthodox setup with 8-bit char and 32-bit int types, then the bits in a are:

0000 1010

The value stored in b is the bitwise inverse of what's in a, which means it contains the following bits, which correspond to 245 decimal:

1111 0101

When an unsigned char is passed to printf():

printf("a = %d\n", a);
printf("b = %d\n", b);

the types shorter than int (the character types and short types — I'm assuming that short is a 16-bit type, which is usually but not necessarily the case) are automatically promoted to int. Since the source type is unsigned char, the value is converted to a positive int value — 10 and 245 in the example code.

Change the type from unsigned char to int and things alter.

a:  0000 0000 0000 0000 0000 0000 0000 1010
b:  1111 1111 1111 1111 1111 1111 1111 0101

and the bit pattern in b corresponds to -11 because of the way 2's complement arithmetic (storage) works. And when these versions of a and b are passed to printf(), there is no conversion necessary, so printf() sees 10 and -11 as the values, and prints accordingly.

The key point is the promotion operation.

In the C standard, it says:

6.5.2.2 Function calls

¶7 If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type. The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments.

Of course, the declared type of printf() is:

int printf(const char * restrict format, ...);

So, the values a and b come after the last declared parameter and are subject to 'default argument promotions'. They're specified (in part) in paragraph 6:

¶6 If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions. …

You have to go back a bit further to find integer promotions:

6.3.1 Arithmetic operands

6.3.1.1 Boolean, characters and integers

¶2 The following may be used in an expression wherever an int or unsigned int may be used:

  • An object or expression with an integer type (other than int or unsigned int) whose integer conversion rank is less than or equal to the rank of int and unsigned int.
  • A bit-field of type _Bool, int, signed int, or 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.58) All other types are unchanged by the integer promotions.

¶3 The integer promotions preserve value including sign. As discussed earlier, whether a ‘‘plain’’ char is treated as signed is implementation-defined.

The concept of rank is defined in §6.3.1.1 ¶1, and I'm not going to quote it (it's fairly long and very detailed).

The key point is that smaller types (like char) are promoted to int, and preserve the value including the sign. And what you're seeing exactly matches that.


Test code

#include <stdio.h>

int main(void)
{
    unsigned char a1 = 10;
    unsigned char b1 = ~a1;
    printf("a1 = %d, b1 = %d\n", a1, b1);

    int a2 = 10;
    int b2 = ~a2;
    printf("a2 = %d, b2 = %d\n", a2, b2);

    return 0;
}

Output:

a1 = 10, b1 = 245
a2 = 10, b2 = -11

Upvotes: 6

kocica
kocica

Reputation: 6467

Unsigned char

a

|128|64|32|16|8|4|2|1|
|0  |0 |0 |0 |1|0|1|0|

equals 10

~ is bit negation

(unsigned char)~a

|128|64|32|16|8|4|2|1|
|1  |1 |1 |1 |0|1|0|1|

equals 245

Since 8b char is smaller than 32b int, the value is extended to 32b but the sign is preserved when calling printf().

Int

Two's complement is usually used for signed operations. Let's expect that sizeof(int) equals 4B (32bit's). (Sizeof int depend's on architecture.)

10 in 4B

|0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |1|0|1|0|

~10 in 4B

|1|1|1|1| |1|1|1|1| |1|1|1|1| |1|1|1|1| |1|1|1|1| |1|1|1|1| |1|1|1|1| |0|1|0|1|

To get value in decimal

  • ~ Negate value
  • Add 1
  • Change sign

So you have

- |0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |0|0|0|0| |1|0|1|1|

and it equals -11 in decimal

What is the use of unsigned char in bitwise negation operation?

By using unsigned char you got 8 bit's unsigned which mean's values 0..255. (2^8 -1)

So for signed char you've got values -127..127. (+/-)2^7 -1

The unsigned char simply means: Use the most significant bit instead of treating it as a bit flag for +/- sign when performing arithmetic operations.

Upvotes: 5

Lundin
Lundin

Reputation: 213892

Whenever ~ is used on an operand of small integer type, such as char, unsigned char, short etc, that operand is always implicitly promoted to type int. This is known as the integer promotion rule.

Meaning that no matter what char type a in your example is, it will get promoted to int which is a signed type. The expression ~a is equivalent to ~(int)10. The result will be (assuming 32 bit CPU) 0xFFFFFFF5, represented in two's complement as -11.

However, when you store this number back into an unsigned char, it will get converted to an unsigned type with value 245. When you declare b as int, this conversion doesn't happen and the value remains -11.

The above is the reason why ~ is a rather dangerous operator to use. In more complex expressions it can create very subtle bugs caused by the silent change of signedness.

Upvotes: 6

Kosimov Sukhrob
Kosimov Sukhrob

Reputation: 19

int variables store 32 bits and the first bit stands for the sign of number. If the bit is on, then the number is negative.

the negative numbers are represented as follows:

-1 | 11111...111
-2 | 11111...110
-3 | 11111...101
-4 | 11111...100

The sequence is almost the same as with positive integers, but in reversed order.

Upvotes: 0

Related Questions