How to bit shift "x" with "y"? - c

I have some trouble with a bit-shift program.
The challenge is to write a program which can shift an unsigned int a number of steps to the left. Both integers are given as input by the user. Thus, given two integers (x and y), the bits in x shall be moved y steps to the left, and the bits which are lost on the left side should be moved to the right. Namely, the bits which are lost outside the most significant are placed in the least significant positions.
To solve the challenge, I have made the following attempt:
#include <stdio.h>
#include <utility.h>
unsigned int bitshift(unsigned int a, unsigned int b)
{
a<<b;
b>>a;
return a,b;
}
int main (void)
{
unsigned int x, y;
printf("Enter two integers (smaller than 32) please:\n");
scanf("%u%u", &x, &y);
printf("Your integers are %u and %u.\n", x, y);
printf("In hexadecimal-format, your integers are %08x and %08x.\n", x, y);
printf("We are now going to perform a bit shift operation\n");
printf("The result of the bitshift operation is:\n");
printf("%u and %u\n", bitshift(x,y));
printf("In hexadecimal: %08x and %08x\n", bitshift(x,y));
while(!KeyHit());
return 0;
}
However, I'm getting an error message when compiling, e.g. "not enough parameters", which I do not understand.
But what I am most wondering is if the bitshift function will do the job?

This is a modification of Barmar's (now deleted) solution for function bitshift with improvements suggested in comments.
Unfortunately, C does not have operators to rotate the bits in a value as might be available in the CPU's instruction set. That's why the operation can be done by moving the least significant bits to the left, moving the most significant bits to the right and combining the results.
To calculate the shift width for shifting the most significant bits to the right, the number of bits in the data type must be calculated using sizeof.
Note that a shift width greater than or equal to the number of bits in the value is undefined behavior (UB). That's why the shift width is calculated modulo the number of bits in the value. Additionally a left shift of 0 would result in UB in the right shift.
#include <stdio.h>
// get CHAR_BITS to make code portable for unusual platforms
#include <limits.h>
unsigned int bitshift(unsigned int a, unsigned int b)
{
// modulo operation to prevent undefined behavior
b %= sizeof a * CHAR_BIT; // sizeof a * 8 on usual platforms
// prevent undefined behavior for right shift
if(b == 0) return a;
unsigned int upper = a << b;
// not portable for unusual platforms
// unsigned int lower = a >> (sizeof a * 8 - b);
unsigned int lower = a >> (sizeof a * CHAR_BIT - b);
return upper | lower;
}
int main (void)
{
unsigned int x, y;
printf("Enter two integers (smaller than 32) please:\n");
scanf("%u%u", &x, &y);
printf("Your integers are %u and %u.\n", x, y);
printf("In hexadecimal-format, your integers are %08x and %08x.\n", x, y);
printf("We are now going to perform a bit shift operation\n");
printf("The result of the bitshift operation is:\n");
printf("%u\n", bitshift(x,y));
printf("In hexadecimal: %08x\n", bitshift(x,y));
return 0;
}
Example input/output:
Enter two integers (smaller than 32) please:
1234567890 12
Your integers are 1234567890 and 12.
In hexadecimal-format, your integers are 499602d2 and 0000000c.
We are now going to perform a bit shift operation
The result of the bitshift operation is:
1613571225
In hexadecimal: 602d2499
Enter two integers (smaller than 32) please:
246 28
Your integers are 246 and 28.
In hexadecimal-format, your integers are 000000f6 and 0000001c.
We are now going to perform a bit shift operation
The result of the bitshift operation is:
1610612751
In hexadecimal: 6000000f

It is enough tho shift right to get the bits which will be shifted out and or it with the value shifted left. To avoid UBs number of bits should be checked.
unsigned rol(unsigned val, unsigned nbits)
{
if(nbits && nbits < CHAR_BIT * sizeof(val))
{
val = (val >> (CHAR_BIT * sizeof(val) - nbits)) | (val << nbits);
}
return val;
}

You actually want to rotate the bits.
// Rotate the bits of a by b to the left and return the result
unsigned int bitshift(unsigned int a, unsigned int b)
{
for (unsigned int i = 0; i < b; i++)
{
unsigned int lowbit = 0;
if (a & 0x80000000)
lowbit = 1;
a <<= 1;
a |= lowbit;
}
return a;
}
This assumes unsigned int is 32 bits. You should be able to adapt it for 64 bits.
Disclaimer:
This is a very naive method though. If you need speed, you should avoid the loop. This can be done but it's more tricky.

Related

Different bits of two given integers

Hey so I have been asked to get the number of different bits between two integers.
I have written the code below which seem to work but only for positive numbers.
I would love to know what am I doing wrong.
printf("Enter 2 numbers:\n");
scanf("%d %d", &num1, &num2);
xor_num = num1 ^ num2;
while (xor_num != 0) {
if (xor_num & 1) {
xor_num = xor_num >> 1;
bits_on += 1;
}
else
xor_num = xor_num >> 1;
}
printf("There are %d diffrent bits\n", bits_on);
Shifting bits on a negative integer has implementation-defined behavior. In your case the sign bit (the most significant bit) is most likely not shifted so the variable xor_num never approaches zero and the loop is infinite. Instead you need to work on an unsigned integer. When you use the scanf function you also need to make sure that the input is valid. It is also a good idea to break out the code which calculates the number of bits into a separate function. Here is one way to do it:
#include <stdio.h>
#include <stdlib.h>
int BitCount(int x)
{
int result = 0;
unsigned int y = x;
while (y != 0) {
result += (y & 1);
y >>= 1;
}
return result;
}
int main(void)
{
int n, x, y;
printf("Enter 2 numbers:\n");
n = scanf("%d %d", &x, &y);
if (n == 2) {
printf("There are %d diffrent bits\n", BitCount(x ^ y));
} else {
fprintf(stderr, "wrong input\n");
exit(EXIT_FAILURE);
}
return 0;
}
When shifting negative values right, it is common for C implementations to copy the sign bit and leave it unchanged, rather than zeroing it. For example, where the four unsigned bits 1000 would be shifted to 0100 and then 0010 0001, and 0000, the four bits with a leading sign bit 1000 would be shifted to 1100, 1110, and then 1111. (The C standard leaves it to the implementation to define this behavior, per C 2018 6.5.7 5.) In this case, when xor_num is negative, xor_num >> 1 leaves the sign bit set, so it never becomes non-negative.
The easiest way to deal with this, presuming you are using int types, is to use unsigned xor_num = num1 ^ num2;. If your C implementation uses two’s complement do, which all regular implementations today do, the conversion from signed int to unsigned int will produce the same bits in xor_num but the shift with xor_num >> 1 will be a logical shift, which zeros the sign bit.

Convert signed int of variable bit size

I have a number of bits (the number of bits can change) in an unsigned int (uint32_t). For example (12 bits in the example):
uint32_t a = 0xF9C;
The bits represent a signed int of that length.
In this case the number in decimal should be -100.
I want to store the variable in a signed variable and gets is actual value.
If I just use:
int32_t b = (int32_t)a;
it will be just the value 3996, since it gets casted to (0x00000F9C) but it actually needs to be (0xFFFFFF9C)
I know one way to do it:
union test
{
signed temp :12;
};
union test x;
x.temp = a;
int32_t result = (int32_t) x.temp;
now i get the correct value -100
But is there a better way to do it?
My solution is not very flexbile, as I mentioned the number of bits can vary (anything between 1-64bits).
But is there a better way to do it?
Well, depends on what you mean by "better". The example below shows a more flexible way of doing it as the size of the bit field isn't fixed. If your use case requires different bit sizes, you could consider it a "better" way.
unsigned sign_extend(unsigned x, unsigned num_bits)
{
unsigned f = ~((1 << (num_bits-1)) - 1);
if (x & f) x = x | f;
return x;
}
int main(void)
{
int x = sign_extend(0xf9c, 12);
printf("%d\n", x);
int y = sign_extend(0x79c, 12);
printf("%d\n", y);
}
Output:
-100
1948
A branch free way to sign extend a bitfield (Henry S. Warren Jr., CACM v20 n6 June 1977) is this:
// value i of bit-length len is a bitfield to sign extend
// i is right aligned and zero-filled to the left
sext = 1 << (len - 1);
i = (i ^ sext) - sext;
UPDATE based on #Lundin's comment
Here's tested code (prints -100):
#include <stdio.h>
#include <stdint.h>
int32_t sign_extend (uint32_t x, int32_t len)
{
int32_t i = (x & ((1u << len) - 1)); // or just x if you know there are no extraneous bits
int32_t sext = 1 << (len - 1);
return (i ^ sext) - sext;
}
int main(void)
{
printf("%d\n", sign_extend(0xF9C, 12));
return 0;
}
This relies on the implementation defined behavior of sign extension when right-shifting signed negative integers. First you shift your unsigned integer all the way left until the sign bit is becoming MSB, then you cast it to signed integer and shift back:
#include <stdio.h>
#include <stdint.h>
#define NUMBER_OF_BITS 12
int main(void) {
uint32_t x = 0xF9C;
int32_t y = (int32_t)(x << (32-NUMBER_OF_BITS)) >> (32-NUMBER_OF_BITS);
printf("%d\n", y);
return 0;
}
This is a solution to your problem:
int32_t sign_extend(uint32_t x, uint32_t bit_size)
{
// The expression (0xffffffff << bit_size) will fill the upper bits to sign extend the number.
// The expression (-(x >> (bit_size-1))) is a mask that will zero the previous expression in case the number was positive (to avoid having an if statemet).
return (0xffffffff << bit_size) & (-(x >> (bit_size-1))) | x;
}
int main()
{
printf("%d\n", sign_extend(0xf9c, 12)); // -100
printf("%d\n", sign_extend(0x7ff, 12)); // 2047
return 0;
}
The sane, portable and effective way to do this is simply to mask out the data part, then fill up everything else with 0xFF... to get proper 2's complement representation. You need to know is how many bits that are the data part.
We can mask out the data with (1u << data_length) - 1.
In this case with data_length = 8, the data mask becomes 0xFF. Lets call this data_mask.
Thus the data part of the number is a & data_mask.
The rest of the number needs to be filled with zeroes. That is, everything not part of the data mask. Simply do ~data_mask to achieve that.
C code: a = (a & data_mask) | ~data_mask. Now a is proper 32 bit 2's complement.
Example:
#include <stdio.h>
#include <inttypes.h>
int main(void)
{
const uint32_t data_length = 8;
const uint32_t data_mask = (1u << data_length) - 1;
uint32_t a = 0xF9C;
a = (a & data_mask) | ~data_mask;
printf("%"PRIX32 "\t%"PRIi32, a, (int32_t)a);
}
Output:
FFFFFF9C -100
This relies on int being 32 bits 2's complement but is otherwise fully portable.

Flipping certain bit in an integer (C language)

I'm trying to get my program to work where a certain bit is being flipped. I have this function called flipbit(int *p, int m). The user needs to input a digit and a bit number. Let's say the user gives the number 8 (00001000) and the bit number 2, so the 2nd bit in 8 should be flipped, which becomes 00001010. How can I program this?
EDIT: I made a stupid mistake, I want to count starting from 0, so the 2nd bit in 8 flipped is actually 00001100 instead of 00001010.
#include <stdio.h>
#include <stdlib.h>
void flipbit(int *p, int m) {
int digit;
digit = *p;
int bit;
bit = &m;
int result;
//printf("The numbers are %d %d", digit, bit);
printf("%d", result);
}
int main() {
int number1;
int number2;
printf("Give number and bit: ");
scanf("%d, %d",&number1, &number2);
flipbit(&number1, &number2);
return 0;
}
Given the bit to flip, you first need to create a mask. Do that by taking the value 1 and left shifting it by the bit number.
Once you have that mask, use the bitwise XOR operator ^ to flip the bit.
int mask = 1 << m;
*p = *p ^ mask;
When checking your source code, there are mixture between pointer and value.
To comply the call of your flipbit() function with the declaration, the call should be:
// first parameter is a pointer and second parameter is a value
flipbit(&number1, number2); // void flipbit(int *p, int m);
Inside the flipbit() function, the mixture continues because digit is a value and p is a pointer. The code should be:
int digit;
// 'digit' is a value and 'p' is a pointer
digit = p[0]; // 'digit' is the first value pointed by 'p'
Same error kind of error with the 'bit' parameter
int bit;
// 'bit' is a value and 'm' is a value
bit = m;
And the result to flip a bit is the XOR operation.
the bit number 2, so the 2nd
Due to your specification, you have to shift only of (bit - 1).
So, in your case:
0x0001(or 0000.0000.0000.0001b) << (2 - 1) = 0x0002(or 0000.0000.0000.0010b)
result is 0x0010(or 0000.0000.0000.1000b) XOR 0x0002(or 0000.0000.0000.0010b) = 0x0012(or 0000.0000.0001.0010b).
int result;
result = digit ^ (0x0001 << (bit - 1));
Did you enter '9, 1' to comply with the scanf("%d, %d",..) ?

Bit Level Operators

One of the few programming assignments I had due was dealing with bit level operators and I was hoping I did this correctly.
#include <stdio.h>
int main(void){
int x;
printf("Enter an x: ");
scanf("%x", &x);
printf("X = %d\n", x);
// Any bit in x is 1
x && printf("A bit in x is 1!\n");
// Any bit in x is 0
~x && printf("A bit in x is 0!\n");
// Least significant byte of x has a bit of 1
(x & 0xFF) && printf("A bit in least significant byte of x is 1!\n");
// Most significant byte of x has a bit of 0
int most = (x & ~(0xFF<<(sizeof(int)-1<<3)));
most && printf("A bit in the most significant byte of x is 0!\n");
return 0;
}
The assignment restricted what we could use so there could be no loops or conditionals and many other restrictions. I get a bit confused with the bit level operators so I was just hoping if there are any errors I could fix it and learn why it was wrong. Thanks.
You shouldn't use signed integers for these operations, because some cases result in undefined / implementation-defined behaviour: Arithmetic bit-shift on a signed integer
int most = (x & ~(0xFF<<(sizeof(int)-1<<3)));
You should negate x, not the right hand side:
int most = (~x & (0xFF<<(sizeof(int)-1<<3)));

Left Bit Shift In C without extension

I was wondering how to get C to not extend my binary number when I bitshift to the left
int main ()
{
unsigned int binary_temp = 0b0100;
binary_temp = binary_temp << 2;
printf("%d", binary_temp);
return 0;
}
When I run that I want a return value of 0 since it has extended past the 4 digits I have, but right now it returns 16 (10000). How would I get C not to extend my number?
Edit: I would like to be able to work with the number in binary form so I need to have only 4 digits, and not just outputting the right number.
It does not extend your number but saves it as unsigned int type which is 4 bytes (32 bits) in size. You only fill the last 4 bits. To treat it as only 4 bits, use Bitwise AND with a Mask value. Here's example code:
int main()
{
unsigned int binary_temp = 0b0100;
binary_temp = (binary_temp << 2) & 0b1111;
printf("%u", binary_temp);
return 0;
}
You can bitwise AND the result with a 4 bit mask value:
binary_temp = (binary_temp << 2) & 0xF;
There is no 0b in standard C. You could use 4.
unsigned int /* prepare for wtf identifier: */
binary_temp = 4;
Left shifting by 2 is multiplying by 4. Why not?
binary_temp *= 4;
... and then reduce modulo 16?
binary_temp %= 16;
What sense is there to using binary operators, in this case? I see none.
The %d directive corresponds to an int argument, but the argument you're giving printf is an unsigned int. That's undefined behaviour.
printf("%u", binary_temp);
I'm sure whichever book you're reading will tell you about the %u directive.

Resources