+ 1

Why does char store 127 and 129 as the same?

Why is the binary value for the two numbers the same? Using unsigned char solves the issue, but I specifically want to know why 129 is converted into 127's binary form. Thanks. https://sololearn.com/compiler-playground/c7nuk5W1JCfh/?ref=app

14th Sep 2024, 8:55 AM
Calvin Jude
Calvin Jude - avatar
7 Réponses
+ 4
Calvin Jude this has to do with the way that this C compiler handles signed char type and promotion from signed char to signed int. When it passes the char argument into the int parameter, it converts the signed char into a signed int. So the value inside the function gets represented as int -127 and the sign bit gets moved from bit 7 up to bit 31. If you adjust either the declaration of char a to be unsigned char a, or the function declaration to take unsigned int, then you will see accurate results.
14th Sep 2024, 9:54 AM
Brian
Brian - avatar
+ 6
The range for signed char is -128 to 127 128 and 129 in your code both overflows so they be clamped to negative 128 and 127 respectively. so literally, it just puts(get_bin(-128));. for __128 puts(get_bin(-127));. for __129
14th Sep 2024, 9:36 AM
RuntimeTerror
RuntimeTerror - avatar
+ 1
Calvin Jude there is more detail to fully explain it. Two more behaviors are entailed. 1) Beware that using num % 2 on a negative number in C evaluates to 0 or -1. The remainder matches the sign of the operand, num. Not a problem here, just beware. 2) Whether you divide by 2 or use bitwise >>, shifting bits of negative numbers in C does not work very well. This is among my chief complaints about C. Dividing a negative value by 2 (num /= 2) can change the original bits because integer division in C truncates (e.g., -63.5 => -63). Note that bit0 keeps getting set to 1, and it fills in 1 bits from the left: -127 = 10000001 -127/2 = -63 = 11000001 -63/2 = -31 = 11100001 -31/2 = -15: = 11110001 ... -1/2 = 0: 11111111 / 2 = 00000000 If you try bitwise shift (num >>= 1), it preserves the low bit but the sign bit stays and propagates downward. -127 = 10000001 -127>>1 = -64 = 11000000 -64>>1 = -32 = 11100000 -32>>1 = -16 = 11110000 ... -2>>1 = -1 = 11111111 -1>>1 = -1 = 11111111 Unsigned fixes all this.
15th Sep 2024, 11:24 AM
Brian
Brian - avatar
0
Brian, here’s how I understand it (feedback on the accuracy would be much appreciated): In signed types, the leftmost bit acts as an indicator for the sign. If that bit is 1, the value is interpreted as negative, be it a char, short, int or a long. For unsigned types, that same bit is used to represent larger positive values. In my case, I provided specific input that set the leftmost bit to 1. Since the value was stored as a signed char, it was treated as a negative number, changing the given int data's meaning. This negative value was then converted into its corresponding negative integer, which caused the unexpected output.
14th Sep 2024, 6:36 PM
Calvin Jude
Calvin Jude - avatar
0
RuntimeTerror, oh right! I think I need to add an additional check for negative numbers in my function, and once the current function completes, call another function to find the two’s complement. That'd prove the accuracy of get_bin
14th Sep 2024, 6:39 PM
Calvin Jude
Calvin Jude - avatar
0
Ok
15th Sep 2024, 7:35 PM
Hùng Phạm
Hùng Phạm - avatar
0
Brian Here are my thoughts, structured into bullets: 1. I see something like -5 % 2 as the 'x' in 2 * (-2) + x = -5, i.e, the remainder 2. It's weird seeing how the sign bit is unaffected by bitwise shift. C *does* treat signed and unsigned quite differently. So I'll keep that in mind when dealing with negative numbers in c (be it ints or floats)
15th Sep 2024, 9:08 PM
Calvin Jude
Calvin Jude - avatar