Pointer assignment - uint16_t - c

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.

Related

Trouble understanding bit shifting as follows

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);
}

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.

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.

Difference in execution of left-shift between literal constant and variable with same value

I am writing a C function which takes a parameter n and returns an int with bit representation of n 1's followed by enough 0's to fill the datatype (32 bits total). My code currently looks like this:
int upperBits(int n) {
int retval = 0 - 1;
int shift = 32 - n;
retval = retval << shift;
return retval;
}
This code fails when n=0, giving a return value of -1, represented by 32 1's, instead of 0. When, however, I replace shift with a literal:
int upperBits(int n) {
int retval = 0 - 1;
int shift = 32 - n;
retval = retval << 32;
return retval;
}
The code works properly, returning 0. I have used print statements to verify that shift = 32 when the function is called with n = 0, so I do not understand why these behave differently. What causes this difference, and how can I circumvent it?
If it is relevant, the code is running on a Linux machine and is compiled with gcc. I am required to use straightline code with only these operators: ! ˜ & ˆ | + << >>
EDIT:
I still do not know exactly what the problem is, or an elegant solution, but this workaround is effective:
int upperBits(int n) {
int retval = 0 - 1;
int shift = 32 - n;
int isnull = !(n);
printf ("%x %x %x \n", retval, shift, n);
retval = retval << (shift - isnull);
retval = retval << isnull;
printf ("%x %x %x \n", retval, shift, n);
return retval;
}
You're performing an illegal left-shift.
Left shifting a negative number invokes undefined behavior, as does shifting by an amount greater than or equal to the bit width of the type in question.
Section 6.5.7 of the C standard regarding Bitwise Shift operators states:
3 The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand. 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.
4 The result of E1 << E2 is E1 left-shifted E2 bit positions;
vacated bits are filled with zeros. If E1 has an unsigned
type, the value of the result is E1 × 2 E2 , reduced modulo one
more than the maximum value representable in the result type.
If E1 has a signed type and nonnegative value, and E1 × 2 E2 is
representable in the result type, then that is the resulting
value; otherwise, the behavior is undefined.
You can correct this by using unsigned types and by checking the size of the shift:
uint32_t upperBits(int n) {
uint32_t retval = 0xffffffff;
if (n <= 0 || n > 32) {
return 0;
} else {
int shift = 32 - n;
retval = retval << shift;
return retval;
}
}

Negative numbers: How can I change the sign bit in a signed int to a 0?

I was thinking this world work, but it does not:
int a = -500;
a = a << 1;
a = (unsigned int)a >> 1;
//printf("%d",a) gives me "2147483148"
My thought was that the left-shift would remove the leftmost sign bit, so right-shifting it as an unsigned int would guarantee that it's a logical shift rather than arithmetic. Why is this incorrect?
Also:
int a = -500;
a = a << 1;
//printf("%d",a) gives me "-1000"
TL;DR: the easiest way is to use the abs function from <stdlib.h>. The rest of the answer involves the representation of negative numbers on a computer.
Negative integers are (almost always) represented in 2's complement form. (see note below)
The method of getting the negative of a number is:
Take the binary representation of the whole number (including leading zeroes for the data type, except the MSB which will serve as the sign bit).
Take the 1's complement of the above number.
Add 1 to the 1's complement.
Prefix a sign bit.
Using 500 as an example,
Take the binary representation of 500: _000 0001 1111 0100 (_ is a placeholder for the sign bit).
Take the 1's-complement / inverse of it: _111 1110 0000 1011
Add 1 to the 1's complement: _111 1110 0000 1011 + 1 = _111 1110 0000 1100. This is the same as 2147483148 that you obtained, when you replaced the sign-bit by zero.
Prefix 0 to show a positive number and 1 for a negative number: 1111 1110 0000 1100. (This will be different from 2147483148 above. The reason you got the above value is because you nuked the MSB).
Inverting the sign is a similar process. You get leading ones if you use 16-bit or 32-bit numbers leading to the large value that you see. The LSB should be the same in each case.
Note: there are machines with 1's complement representation, but they are a minority. The 2's complement is usually preferred because 0 has the same representation, i.e., -0 and 0 are represented as all-zeroes in the 2's complement notation.
Left-shifting negative integers invokes undefined behavior, so you can't do that. You could have used your code if you did a = (unsigned int)a << 1;. You'd get 500 = 0xFFFFFE0C, left-shifted 1 = 0xFFFFFC18.
a = (unsigned int)a >> 1; does indeed guarantee logical shift, so you get 0x7FFFFE0C. This is decimal 2147483148.
But this is needlessly complex. The best and most portable way to change the sign bit is simply a = -a. Any other code or method is questionable.
If you however insist on bit-twiddling, you could also do something like
(int32_t)a & ~(1u << 31)
This is portable to 32 bit systems, since (int32_t) guarantees two's complement, but 1u << 31 assumes 32 bit int type.
Demo:
#include <stdio.h>
#include <stdint.h>
int main (void)
{
int a = -500;
a = (unsigned int)a << 1;
a = (unsigned int)a >> 1;
printf("%.8X = %d\n", a, a);
_Static_assert(sizeof(int)>=4, "Int must be at least 32 bits.");
a = -500;
a = (int32_t)a & ~(1u << 31);
printf("%.8X = %d\n", a, a);
return 0;
}
As you put in the your "Also" section, after your first left shift of 1 bit, a DOES reflect -1000 as expected.
The issue is in your cast to unsigned int. As explained above, the negative number is represented as 2's complement, meaning the sign is determined by the left most bit (most significant bit). When cast to an unsigned int, that value no longer represents sign but increases the maximum value your int can take.
Assuming 32 bit ints, the MSB used to represent -2^31 (= -2147483648) and now represents positive 2147483648 in an unsigned int, for an increase of 2* 2147483648 = 4294967296. Add this to your original value of -1000 and you get 4294966296. Right shift divides this by 2 and you arrive at 2147483148.
Hoping this may be helpful: (modified printing func from Print an int in binary representation using C)
void int2bin(int a, char *buffer, int buf_size) {
buffer += (buf_size - 1);
for (int i = buf_size-1; i >= 0; i--) {
*buffer-- = (a & 1) + '0';
a >>= 1;
}
}
int main() {
int test = -500;
int bufSize = sizeof(int)*8 + 1;
char buf[bufSize];
buf[bufSize-1] = '\0';
int2bin(test, buf, bufSize-1);
printf("%i (%u): %s\n", test, (unsigned int)test, buf);
//Prints: -500 (4294966796): 11111111111111111111111000001100
test = test << 1;
int2bin(test, buf, bufSize-1);
printf("%i (%u): %s\n", test, (unsigned int)test, buf);
//Prints: -1000 (4294966296): 11111111111111111111110000011000
test = 500;
int2bin(test, buf, bufSize-1);
printf("%i (%u): %s\n", test, (unsigned int)test, buf);
//Prints: 500 (500): 00000000000000000000000111110100
return 0;
}

Resources