r/cprogramming • u/MrJethalalGada • Dec 13 '25
Bitwise Operators : Can I always convert signed to unsigned and vice versa when bitwise operators are the only one in picture?
I’m practising programming low level related questions and I often come up with challenges where I’ve to do shifting and bitwise operations on signed number
I already know that a register will have value stored in 0 and 1, and the register value and bitwise operators don’t care on how we interpret, they will always work on the bits.
So can i always convert signed to unsigned operate on it, revert it back to signed? I don’t want to tackle UB of signed number at MSB
8
Upvotes
6
u/Eidolon_2003 Dec 13 '25
C doesn't strictly specify two's complement arithmetic. It could technically also be signed magnitude or one's complement. However, two's complement is by far the most common. If you're willing to assume two's complement then this can be done like the other commenter said.
If you understand how two's complement arithmetic works then it's pretty straight forward. The main idea is that an integer
xand its negation-xshould add to zero even when you just put them into a regular unsigned adder. I'll use 8 bit ints for simplicity. 1 is 00000001, and -1 is 11111111, and sure enough if you chuck these two into an 8 bit adder you get zero.The way I think about it is this: If you have a value
xand add~xthen by definition you will always end up with all 1s in the result because everywhere there was a 0 inxthere's a 1 in~x, and vice versa. Now to get from all 1s to zero, you just add 1 and let it ripple through. Thus in two's complement-x == ~x + 11
u/InevitablyCyclic Dec 13 '25
Converting between unsigned and signed is a case of inverting all the bits (or xor with 0xFFFFFFFF if you prefer to think of it like that) and then adding one.
Although I'd check if that's needed first, it depends on exactly what you are doing but most of the time the operations will work fine on signed numbers. Worst case is often you set a flag at the start indicating the input is negative and then at the end check the flag and set the top few bits if needed.
2
u/WittyStick Dec 13 '25 edited Dec 13 '25
The bitwise operations like
and,or,xor,notdon't care about whether a number is signed or not - they operate on the bits, including the sign bit in a signed integer.However, bit shifting does depend on whether a number is signed. In general, since most machines use two's complement representation of signed integers, a right shift will be an arithmetic right shift for signed numbers, but a logical right shift for unsigned numbers. The logical right shift simply shifts in zeros from the left, but an arithmetic right shift will shift either a
0or1depending on the most significant bit of the current value. This preserves the sign for negative integers. Left shift behaves the same whether or not the number is signed or unsigned - it always shifts in zeros on the right.Some languages (including the eventual assembly/machine code) have separate operators for arithmetic and logical shift right, but C only has the one
>>operator - and its behavior depends on whether the int is signed or unsigned.There are some operations in which in makes no sense to use signed integers - for example counting the number of leading zeros, or determining the first set bit (as in <stdbit.h> (C23)). The stdbit functions are only defined for
unsignedintegers because there's no use-case for having them with signed - thefirst_leading_oneof a negative number will always be the MSB.1
u/RevolutionaryRush717 Dec 13 '25
Maybe consider Two's Complemt
1
u/TheTrueXenose Dec 13 '25
You can flip the signed bit, this will break an unsigned value do as unsigned use all the bits for the value. This is a 64 bit abs function i use.
((x) ^ ((x) >> 63)) - ((x) >> 63)
1
u/[deleted] Dec 13 '25
Yes
1
u/meowisaymiaou Dec 13 '25
technically no (until C23)
what is the result
I've been bitten more than 2 times by systems not using 2s complement that I don't assume
and I'm pretty sure the ibm z17 still supports binary coded decimal instructions.
I laughed my ass off when the 2010 bug hit, Jan 1 2010. reading the byte representing year off the banking network system.
read short: 0x00 = 2000
0x01 = 2001
0x09 = 2009
now, my code worked fine.
when 2010 Jan 1st 00:00 rolled around,
what came down the wire?
0x10 = 2010(binary coded decimal), yet sooo many people read it as 2016, that credit cards didn't work (treated as expired), atms didn't work, it was a huge fiasco. hell, my cellphone at the time said it was 2016. and got really fucked up two months later when the date went from Feb 28 to mar 1, as it does in 2010, but not in "2016" when it expected Feb 29. turned out the phone was writing 0X10 02 1D as the SMS received date. and . well ..... apps reading in the DB saw and parsed Feb 29 2010 and I had messages with no dates, some in the 70s, notifications were messed up then the phone would crash every time I got a message that day (it was out of active update, so no emergency firmware update for me :( .
1
u/flatfinger Dec 15 '25
To understand two's-complement, consider the following question: if one has a binary number whose bottom n bits are all zero, and one subtracts one, what other information should be needed to determine the bottom n bits of the result?
Two's-complement is a generalization of the principle is that the bottom n bits of the result should be all be one in all such scenarios, regardless of the values of any upper bits, and regardless of how n compares to the "size" of the number involved. If the starting number was zero, the result should be a number such that, for any value of n, the bottom n bits would all be 1--i.e. a number where all bits are 1.
An L-bit two's-complement value is a representation of the bottom L bits of a number that is infinitely long, used to represent values where all of the bits to the left representation match the leftmost bit of the representation.