So I am doing some bit-shifting and i have come to the following problem, that i would be more than grateful to get an answer to:
As an argument I'm allowed to pass the size of 1 byte.
The first 4 bits represent a numerator. The last 4 bits represent the denominator.
The following code works and gives the correct output:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int argc, char** argv)
{
for(int i = 1; i < argc; i++)
{
unsigned char numerator = atoi(argv[i]);
numerator = (numerator >> 4);
numerator = (numerator << 4);
unsigned char denominator = atoi(argv[i]);
denominator = (denominator << 4);
denominator = (denominator >> 4);
printf("%d/%d\n", numerator, denominator);
}
return 0;
}
But if i substitute the bit shifting part like this, the denominator gives the same output as the numerator:
unsigned char numerator = atoi(argv[i]);
numerator = (numerator >> 4) << 4;
unsigned char denominator = atoi(argv[i]);
denominator = (denominator << 4) >> 4;
sample input would be:
./test 1
./test 16
output given:
0/1
16/16
expected output:
0/1
16/0
Thanks in advance for any sort of help.
When arithmetic expressions are evaluated in C, any integral types smaller than int
are promoted to int
before the calculations are performed.
So this code:
unsigned char denominator = atoi(argv[i]);
denominator = (denominator << 4);
denominator = (denominator >> 4);
results in the following sequence (each box represents 4 bits, and the text in the box is a hex digit):
Note that the assignment denominator = (denominator << 4);
forces the compiler to convert the value back to an unsigned char
. Then on the next line of code, the compiler needs to promote the unsigned char
back to an int
.
But this code:
unsigned char denominator = atoi(argv[i]);
denominator = (denominator << 4) >> 4;
skips the conversion back to unsigned char
and the second promotion to int
. So the sequence is:
Note that the final value is the same as the original value, since the shifting was performed using 32-bits, and nothing was shifted off the left side of the 32-bit value.
The numerator doesn't have the same problem. Because the numerator is shifted right first, the bits on the right are lost. The promotion to int
has no effect on the results. Here's the sequence for the numerator:
It seems that the values are being cast to a larger integer type (such as int), and when the shifts are performed, the upper bits are being preserved in the larger int type, then the result is cast back to unsigned char after both shifts are complete.
I would use a bitmask like this, instead of shifting:
...
unsigned char data = atoi(argv[i]);
unsigned char numerator = data & 0xf0;
unsigned char denominator = data & 0xf;
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With