Trouble understanding bit shifting as follows - c

So I have written the code below which takes an unsigned int , shifts its bits 6 positions to the left then replaces the empty final 6 bits with another int value. However, when I run the code say with value 15, the first step works and I get a value of 960 (so shifting left by 6 works). But the or step does not seem to work and I get -1 when I actually need to get 1111111111111111 or i.e. 65535 (note the operand value in this case is -1)? Any help would be greatly appreciated. I understand it is something to maybe do with my types but s->data was defined as an unsigned int whilst operand is defined as an int so I do not know why the output of s->data gives a negative value.
typedef struct state { int x, y, tx, ty; unsigned char tool; unsigned int start, data; bool end;} state;
void dataCommand(int operand, state *s) {
// shifts bits of current data fields six positions to left
printf("BEFORE SHIFTING %d\n", s->data);
s->data = s->data << 6;
printf("AFTER SHIFTING %d\n", s->data);
printf("OPERAND IS %d\n", operand);
// last 6 bits replaced with operand bits of the command
s->data = (s->data | operand);
printf("AFTER OR %d\n", s->data);
}

When operand is -1 it is actually 0xffffffff (32 ones in binary).
So when you are ORing you get back 32 ones which is still -1.
Maybe what you wanted to do was masking 6 bits off the operand :
s->data = (s->data << 6) | (operand & 0b111111);

You must mask the operand to select which bits are combined into the result.
-1 is converted to unsigned int in the s->data | operand expression, to the value UINT_MAX that has all bits set, hence oring operand sets all bits in the result, giving it a value of UINT_MAX, but since you use %d to output the value, you get -1.
Modify the code this way:
typedef struct state {
int x, y, tx, ty;
unsigned char tool;
unsigned int start, data;
bool end;
} state;
void dataCommand(int operand, state *s) {
// shifts bits of current data fields six positions to left
printf("BEFORE SHIFTING %u\n", s->data);
s->data = s->data << 6;
printf("AFTER SHIFTING %u\n", s->data);
printf("OPERAND IS %d (%#x)\n", operand, operand);
// last 6 bits replaced with operand bits of the command
s->data = s->data | (operand & 0x3F);
printf("AFTER OR %u\n", s->data);
}

Related

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

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.

strange behaviour of char

If char a = -128; it is represented in binary as 10000000.
but when I shift this binary equivalent to the left side by by one bit it gives me -256 for which my brain doesn't make any sense.
Can anyone explain it to me how this strange behaviour comes?
int main(){
char a=-128;
printf("%d",a<<1);
return 0;
}
-128 on an int variable is 0xffffff80.
The shifting left result is 0xffffff00 that is -256.
You can test it with this code:
int main(void)
{
int n = -128;
printf("Decimal value = %d\n", n);
printf("Hex value = %x\n", n);
n<<=1;
printf("Decimal value = %d\n", n);
printf("Hex Value = %x\n", n);
return 0;
}
EDIT
In your code printf is promoting your char variable to int before shifting it.
As per the rule# of shifting operator,
The integer promotions are performed on each of the operands. [...]
So, while using a<<1 as the argument for printf(), a being of type char and 1 being the type of int (literal), a value is promoted to type int and then, the shifting will be performed, then the result will be printed out as an int value.
[#] - C11, chapter §6.5.7, Bitwise shift operators

Pointer assignment - uint16_t

I was looking at a problem from cs61c (ucb).
I have the following method:
void lfsr_calculate(uint16_t *reg) {
uint16_t result = compute_bit_val(*reg);
printf("reg value: %d", *reg);
printf("bit val result: %d", result);
printf("bit val result shifted: %d", result << 16);
*reg >>= 1;
printf("bit val result shifted plus zero: %d", *reg + (result << 16));
*reg = (uint16_t) *reg + (result << 16);
printf("new reg: %d", *reg);
}
If *reg is 1, my method compute_bit_val returns 1. The print output is
1
1
65536
65536
**0**
?!?!?! I am pulling out my hair, I don't know why the last part is zero, for some reason the assignment is not working. I tried this with and without casting, and it gives the same result.
In the last step, you assign 65536 to *reg which is uint16_t. However uint16_t can only store values from 0 to 65535, so it gets adjusted via modular arithmetic to have value 0. (aka. wraps around).
You may be overlooking that integer arithmetic is always performed in at least int precision; narrower types are immediately promoted to int before computing the result of any arithmetic operator.

cast without * operator

Could someone explain to me what's happening to "n" in this situation?
main.c
unsigned long temp0;
PLLSYS0_FWD_DIV_A_DECODE(n);
main.h
#define PLLSYS0_FWD_DIV_A_DECODE(n) ((((unsigned long)(n))>>8)& 0x0000000f)
I understand that n is being shifted 8 bits and then anded with 0x0000000f. So what does (unsigned long)(n) actually do?
#include <stdio.h>
int main(void)
{
unsigned long test1 = 1;
printf("test1 = %d \n", test1);
printf("(unsigned long)test1 = %d \n", (unsigned long)(test1));
return 0;
}
Output:
test1 = 1
(unsigned long)test1 = 1
In your code example, the cast doesn't make much sense because test1 is already an unsigned long, but it makes sense when the macro is used on a different type like unsigned char etc.
Also you should use %lu in printf to print unsigned long.
printf("(unsigned long)test1 = %lu\n", (unsigned long)(test1));
// ^^
It widens it to be the size of an unsigned long. Imagine if you called this with a char and shifted it 8 bits to the right, the anding wouldn't work the same.
Also just found this (look under right-shift operator) for why it's unsigned. Apparently unsigned forces a logical shift in which the left-most bit is replaced with a zero for each position shifted. Whereas a signed value shifted performs an arithmetic shift where the left-most bit is replaced by the dropped rightmost bit.
Example:
11000011 ( unsigned, shifted to the right by 1 )
01100001
11000011 ( signed, shifted to the right by 1 )
11100001
Could someone explain to me what's happening to "n" in this situation?
You are casting n to unsigned long.
So what does (unsigned long)(n) actually do?
It will promote n to unsigned long.
Casting the input is all it's doing before the bit shift and the anding. Being careful about order if operations and precedence of operators. It's pretty ugly.
But looks like they're avoiding hitting the sign bit and by doing this instead of a function, there's no type checking on n.
It's just ugly.
Better form would be to have a clean clear function that has input type checking.
That ensures that n has the proper size (in bits) and most importantly is treated as unsigned. As the shift operators perform sign extension, when a number is signed and negative, the extension will be done with 1 not zero. It means that a negative number shifted will always result in a negative number.
For example:
int main()
{
long i = -1;
long x, y;
x = ((unsigned long)i) >> 8;
y = i >> 8;
printf("%ld %ld\n", x, y);
}
On my machine it outputs:
72057594037927935 -1
Because of the sign extension in y, the number continues to be -1:

bit shifting in C, unexpected result

when i pass n = 0x0, i get 0xffffffff on the screen
which i expect should be 0x00000000
as i shift the word by 32 bits
(Just Ignore the x! I didn't use it inside the function.)
void logicalShift(int x, int n) {
int y = 32;
int mask = 0xffffffff;
printf("mask %x", mask << (y-n));
}
One of the interesting point is
void logicalShift(int x, int n) {
int y = 32;
int mask = 0xffffffff;
printf("mask %x", mask << 32);
}
this will output what i expected. Do i miss out anything?
Thank you!
Im running on ubuntu
A shift left of 32 bits on a 32 bit value has undefined results. You can only shift 0 to 31 bits.
See also here: Why doesn't left bit-shift, "<<", for 32-bit integers work as expected when used more than 32 times?
Here is the relevant quote from the C11 draft §6.5.7.3;
If the value of the right operand is negative or is greater than or
equal to the width of the promoted left operand, the behavior is
undefined.
In other words, the result is undefined, and the compiler is free to generate any result.

Resources