Reputation: 27
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
Reputation: 670
In C, int and char has to types
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
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 todouble
. 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
orunsigned int
) whose integer conversion rank is less than or equal to the rank ofint
andunsigned int
.- A bit-field of type
_Bool
,int
,signed int
, orunsigned 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 anint
; otherwise, it is converted to anunsigned 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.
#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
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 valueSo 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
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
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