right left shift bits in C - c

I did a small test on bit shifting in C, and all of the shifts by 0, 8, 16 bits are OK and I understood what's happening.
But the 32 bits right or left shift which is not clear to me, the variable I'm doing the test with is 32-bit long.
Then, I changed the 32-bit variables which would hold the shifting results, but 32-bit right left shifts are the same!
Here's my code:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
int main() {
uint32_t code = 0xCDBAFFEE;
uint64_t bit32R = code >> 32;
uint16_t bit16R = code >> 16;
uint8_t bit8R = code >> 8;
uint8_t bit0R = code >> 0;
uint64_t bit32L = code << 32;
uint16_t bit16L = code << 16;
uint8_t bit8L = code << 8;
uint8_t bit0L = code << 0;
printf("Right shift:\nbit32R %.16x\nbit16R %x\nbit8R %x\nbit0R %x\n\n",
bit32R, bit16R, bit8R, bit0R);
printf("Left shift:\nbit32L %.16x\nbit16L %x\nbit8L %x\nbit0L %x\n\n",
bit32L, bit16L, bit8L, bit0L);
}
Here's the result I get:
Right shift:
bit32R 00000000cdbaffee
bit16R 0
bit8R cdba
bit0R ff
Left shift:
bit32L 00000000cdbaffee
bit16L 0
bit8L 0
bit0L 0
Process returned 61 (0x3D) execution time : 0.041 s
Press any key to continue.

Right shifting an integer by a number of bits equal or greater than its size is undefined behavior.
C11 6.5.7 Bitwise shift operators
Syntax
shift-expression: additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
Constraints
Each of the operands shall have integer type.
Semantics
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.
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 × 2E2, reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.
The size of int on your platform seems to be at most 32 bits, so the initializers for bit32R and bit32L have undefined behavior.
The 64-bit expressions should be written:
uint64_t bit32R = (uint64_t)code >> 32;
and
uint64_t bit32L = (uint64_t)code << 32;
Furthermore, the formats used in printf are not correct for the arguments passed (unless int has 64 bits, which would produce different output).
Your compiler does not seem to be fully C99 compliant, you should add a final return 0; statement at the end of the body of function main().
Here is a corrected version:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
int main(void) {
uint32_t code = 0xCDBAFFEE;
uint64_t bit32R = (uint64_t)code >> 32;
uint16_t bit16R = code >> 16;
uint8_t bit8R = code >> 8;
uint8_t bit0R = code >> 0;
uint64_t bit32L = (uint64_t)code << 32;
uint16_t bit16L = code << 16;
uint8_t bit8L = code << 8;
uint8_t bit0L = code << 0;
printf("Right shift:\n"
"bit32R %.16"PRIx64"\n"
"bit16R %"PRIx16"\n"
"bit8R %"PRIx8"\n"
"bit0R %"PRIx8"\n\n",
bit32R, bit16R, bit8R, bit0R);
printf("Left shift:\n"
"bit32L %.16"PRIx64"\n"
"bit16L %"PRIx16"\n"
"bit8L %"PRIx8"\n"
"bit0L %"PRIx8"\n\n",
bit32L, bit16L, bit8L, bit0L);
return 0;
}
The output is:
Right shift:
bit32R 0000000000000000
bit16R cdba
bit8R ff
bit0R ee
Left shift:
bit32L cdbaffee00000000
bit16L 0
bit8L 0
bit0L ee
this might not be what you expect, because the types of the variables are somewhat inconsistent.

One problem is that you are using %x to print a 64-bit integer. You should use the correct format specifier for each variable. There are macros for this available:
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
// ...
printf("64 bit result: %" PRIx64 "\n", bit32R);
printf("16 bit result: %" PRIx16 "\n", bit16R);
printf("8 bit result: %" PRIx8 "\n", bit8R);
More information can be found here.

You are not doing 64 bit left shift there, because code is uint32_t, so compiler uses 32bit version of operator. Also, you should tell print to use long long (same as uint64_t)
#include <cstdint>
#include <stdio.h>
int main ()
{
uint32_t code = 0xCDBAFFEE;
uint64_t bit32R=((uint64_t)code)>>32;
uint16_t bit16R=code>>16;
uint8_t bit8R=code>>8;
uint8_t bit0R=code>>0;
uint64_t bit32L=((uint64_t)code)<<32;
uint16_t bit16L=code<<16;
uint8_t bit8L=code<<8;
uint8_t bit0L=code<<0;
printf("Right shift:\nbit32R %llx\nbit16R %x\nbit8R %x\nbit0R %x\n\n", bit32R,bit16R,bit8R,bit0R);
printf("Leftt shift:\nbit32L %llx\nbit16L %x\nbit8L %x\nbit0L %x", bit32L,bit16L,bit8L,bit0L);
}
Result is:
Right shift:
bit32R 0
bit16R cdba
bit8R ff
bit0R ee
Leftt shift:
bit32L cdbaffee00000000
bit16L 0
bit8L 0
bit0L ee
You should use the macros defined in inttypes.h if you have C99 compliant compiler, sadly some platforms do not have those definitions. Format descriptors for printf are platform-dependent.

Related

Why left shift 24 bits changed the value of unsigned long in C?

I expect 0b11010010 << 24 should be the same value as 0b11010010000000000000000000000000.
I tested it in C, 0b11010010 << 24 doesn't work as expected if we saved it in c unsigned long.
Does anyone know how C unsigned long works like this?
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
int main(){
unsigned long a = 0b11010010000000000000000000000000;
unsigned long b = 0b11010010 << 24;
bool isTheSame1 = a == b;
printf("isTheSame1 %d \n",isTheSame1);
bool isTheSame2 = 0b11010010000000000000000000000000 == (0b11010010 << 24);
printf("isTheSame2 %d",isTheSame2);
}
isTheSame1 should be 1 but it prints 0 as following
isTheSame1 0
isTheSame2 1
Compiled and executed by gcc main.c && ./a.out
gcc --version
Apple clang version 14.0.0 (clang-1400.0.29.202)
Target: x86_64-apple-darwin22.2.0
Thread model: posix
Updated
As Allan Wind pointed out, I added UL suffix and now it works as expected.
unsigned long a = 0b11010010000000000000000000000000UL;
unsigned long b = 0b11010010UL << 24;
bool isTheSame1 = a == b;
printf("isTheSame1 %d \n",isTheSame1);
bool isTheSame2 = 0b11010010000000000000000000000000UL == (0b11010010UL << 24);
printf("isTheSame2 %d",isTheSame2);
The constant 0b11010010 has type int which is signed. Assuming an int is 32 bits, the expression 0b11010010 << 24 will shift a "1" bit into the sign bit. Doing so triggers undefined behavior which is why you're getting strange results.
Add the UL suffix to the constant to give it type unsigned long, then the shift will work as expected.
unsigned long b = 0b11010010UL << 24;
You are doing a left shift of a signed value (see good answer of #dbush)
In absence of suffixes numbers have int or double types
b = 0b11010010 ; /* type int */
b = 1.0; /* type double */
If you want want b in your example as unsigned long use a suffix:
b = 0b11010010UL; /* type unsigned long */
or a cast:
b = (unsigned long)0b11010010; /* type unsigned long */
With 32-bit (or smaller) int, 0b11010010 << 24 is undefined behaver (UB). It attempts to shift into the sign bit.
When int is 32-bit (common), this often results in a negative value corresponding to the bit pattern 11010010-00000000-00000000-00000000.
When a negative value is saved as an unsigned long, ULONG_MAX + 1 is added to it. With a 64-bit unsigned long the value has the bit pattern:
11111111-11111111-11111111-11111111-11010010-00000000-00000000-00000000
This large unsigned long in not equal to 0b11010010000000000000000000000000UL and so the output of "isTheSame1 0".
Had OP's long been 32-bit, it "might" have worked as OP had intended - yet unfortunately still replying on UB.
Appending an L
32-bit unsigned long: 0b11010010 << 24 suffers the same UB problem as above - yet might have "worked".
64-bit unsigned long: 0b11010010L is also long and 0b11010010L << 24 becomes the value 0b11010010000000000000000000000000, the same value as a.
Appending an U
32-bit unsigned: 0b11010010U << 24 becomes the value 0b11010010000000000000000000000000, the same value as a.
16-bit unsigned: 0b11010010U << 24 is undefined behavior as the shift is too great. Often the UB results in the same as 0b11010010U << (24-16), yet this is not reliably done.
Appending an UL
32 or 64-bit unsigned long: 0b11010010UL << 24 becomes the value 0b11010010000000000000000000000000, the same value as a.
Since the left hand side of the = of the below is unsigned long, better for the right hand side constant to be unsigned long.
unsigned long b = 0b11010010 << 24; // Original
unsigned long b = 0b11010010UL << 24; // Better

How do I resolve the following error in my bit shifting C code?

Can anyone help me with the below? Say I have the binary value int colour which is 255 or i.e.
00000000 00000000 000000000 11111111
in binary. How can I perform shifting to get
11111111 11111111 11111111 00000000
I tried making 4 values of 0xff, 0xff00, 0xff0000, 0xff000000 and was going to OR them but when I print these values out I get the following error:
converter.c:66:23: runtime error: left shift of 255 by 24 places cannot be represented in type 'int'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior converter.c:66:23
in
VALS ARE ff, ff00, ff0000, ff000000
Below is my code any help would be greatly appreciated
int val1 = colour;
int val2 = (colour << 8);
int val3 = (colour << 16);
int val4 = (colour << 24);
//unsigned int val5 = 0;
printf("VALS ARE %x, %x, %x, %x\n" , val1, val2, val3, val4);
//rowElement(colour, sketch);
You're getting an error because you're shifting a value into the sign bit of an int. If you shift a 1 into that bit, you trigger undefined behavior.
This is described in section 6.5.7p4 of the C standard regarding bitwise shift operators:
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 × 2E2, reduced modulo one more
than the maximum value representable in the result type. If E1
has a signed type and nonnegative value, and E1 × 2E2 is
representable in the result type, then that is the resulting
value; otherwise, the behavior is undefined.
Change the type of each of your variables to unsigned int. Then you can freely shift into any of the bits, as long as you don't shift by 32 bits or more, assuming an int is 32 bits.
It is enough to write
int x = 255;
x ~= x;
Or it will be better to declare the variable x as having the type unsigned int.
unsigned int x = 255;
x ~= x;
As for the shift operator then according to the C Standard (6.5.7 Bitwise shift operators)
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 × 2E2, reduced modulo one more than the maximum value
representable in the result type. If E1 has a signed type and
nonnegative value, and E1 × 2E2 is representable in the result type,
then that is the resulting value; otherwise, the behavior is
undefined.
To reverse the bytes in ARGB color or any 32-bit unsigned integer, shift to the right, then AND with 0xff For example, to get 44 from 0x11223344 we need just 0x11223344 & 0xff To get 33, shift right by 8 bits -> 0x00112233 and then AND with 0xff again.
Left-shift is needed to build a 32-bit integer again.
int main(void)
{
unsigned int colour = 0x11223344;
unsigned char byte0, byte1, byte2, byte3;
byte0 = (colour ) & 0xff;
byte1 = (colour >> 8 ) & 0xff;
byte2 = (colour >> 16) & 0xff;
byte3 = (colour >> 24) & 0xff;
unsigned int reversed = byte0 << 24 | byte1 << 16 | byte2 << 8 | byte3;
printf("%08X\n", colour);
printf("%08X\n", reversed);
return 0;
}
Output
11223344
44332211

Bit Shifting: Shift Count >= Width Of Type

The code below, when compiled, throws a warning caused by line 9:
warning: shift count >= width of type [-Wshift-count-overflow]
However, line 8 does not throw a similar warning, even though k == 32 (I believe). I'm curious why this behavior is occurring? I am using the gcc compiler system.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int bit_shift(unsigned x, int i){
int k = i * 8;
unsigned n = x << k; /* line 8 */
unsigned m = x << 32; /* line 9 */
return 0;
}
int main(){
bit_shift(0x12345678, 4);
return 0;
}
The value of k in bit_shift is dependent on the parameter i. And because bit_shift is not declared static it is possible that it could be called from other translation units (read: other source files).
So it can't determine at compile time that this shift will always be a problem. That is in contrast to the line unsigned m = x << 32; which always shifts by an invalid amount.
I think why Line 8 does not throw a warning is because left shifting an unsigned int32 >= 32 bits is NOT an undefined behavior.
C standard (N2716, 6.5.7 Bitwise shift operators) says:
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

store 2 signed shorts in one unsigned int

This is given:
signed short a, b;
a = -16;
b = 340;
Now I want to store these 2 signed shorts in one unsigned int and later retrieve these 2 signed shorts again. I tried this but the resulting shorts are not the same:
unsigned int c = a << 16 | b;
signed short ar, br;
ar = c >> 16;
br = c & 0xFFFF;
OP almost had it right
#include <assert.h>
#include <limits.h>
unsigned ab_to_c(signed short a, signed short b) {
assert(SHRT_MAX == 32767);
assert(UINT_MAX == 4294967295);
// unsigned int c = a << 16 | b; fails as `b` get sign extended before the `|`.
// *1u insures the shift of `a` is done as `unsigned` to avoid UB
// of shifting into the sign bit.
unsigned c = (a*1u << 16) | (b & 0xFFFF);
return c;
}
void c_to_ab(unsigned c, signed short *a, signed short *b) {
*a = c >> 16;
*b = c & 0xFFFF;
}
Since a has a negative value,
unsigned int c = a << 16 | b;
results in undefined behavior.
From the C99 standard (emphasis mine):
6.5.7 Bitwise shift operators
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 x 2E2, reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1 x 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
You can explicitly cast the signed short to unsigned short to get a predictable behavior.
#include <stdio.h>
int main()
{
signed short a, b;
a = -16;
b = 340;
unsigned int c = (unsigned short)a << 16 | (unsigned short)b;
signed short ar, br;
ar = c >> 16;
br = c & 0xFFFF;
printf("ar: %hd, br: %hd\n", ar, br);
}
Output:
ar: -16, br: 340
This is really weird, I've compiled your code and it works for me
perhaps this is undefined behavior I'm not sure, however if I were you
I'd add castings to explicitly avoid some bit loss that may or may not be caused by abusing two complement or compiler auto casting....
In my opinion what's happening is probably you shifting out all the bits in
a... try this
unsigned int c = ((unsigned int) a) << 16 | b;
This is because you are using an unsigned int, which is usually 32 bits and a negative signed short which is usually 16 bits.
When you put a short with a negative value into an unsigned int, that "negative" bit is going to be interpreted as part of a positive number.
And so you get a vastly different number in the unsigned int.
Storing two positive numbers would solve this problem....but you might need to store a negative one.
Not sure if this way of doing is good for portability or others but I use...
#ifndef STDIO_H
#define STDIO_H
#include <stdio.h>
#endif
#ifndef SDTINT_H
#define STDINT_H
#include <stdint.h>
#endif
#ifndef BOOLEAN_TE
#define BOOLEAN_TE
typedef enum {false, true} bool;
#endif
#ifndef UINT32_WIDTH
#define UINT32_WIDTH 32 // defined in stdint.h, inttypes.h even in libc.h... undefined ??
#endif
typedef struct{
struct{ // anonymous struct
uint32_t x;
uint32_t y;
};}ts_point;
typedef struct{
struct{ // anonymous struct
uint32_t line;
uint32_t column;
};}ts_position;
bool is_little_endian()
{
uint8_t n = 1;
return *(char *)&n == 1;
}
int main(void)
{
uint32_t x, y;
uint64_t packed;
ts_point *point;
ts_position *position;
x = -12;
y = 3457254;
printf("at start: x = %i | y = %i\n", x, y);
if (is_little_endian()){
packed = (uint64_t)y << UINT32_WIDTH | (uint64_t)x;
}else{
packed = (uint64_t)x << UINT32_WIDTH | (uint64_t)y;
}
printf("packed: position = %llu\n", packed);
point = (ts_point*)&packed;
printf("unpacked: x = %i | y = %i\n", point->x, point->y); // access via pointer
position = (ts_position*)&packed;
printf("unpacked: line = %i | column = %i\n", position->line, position->column);
return 0;
}
I like the way I do as it's offer lots of readiness and can be applied in manay ways ie. 02x32, 04x16, 08x08, etc. I'm new at C so feel free to critic my code and way of doing... thanks

bitwise shifiting question

if i have int temp=(1<<31)>>31. How come the temp becomes -1?
how do i get around this problem?
thanks
Ints are signed by default, which usually means that the high bit is reserved to indicate whether the integer is negative or not. Look up Two's complement for an explanation of how this works.
Here's the upshot:
[steven#sexy:~]% cat test.c
#include <stdint.h>
#include <stdio.h>
int main(int argc, char **argv[]) {
uint32_t uint;
int32_t sint;
int64_t slong;
uint = (((uint32_t)1)<<31) >> 31;
sint = (1<<31) >> 31;
slong = (1L << 31) >> 31;
printf("signed 32 = %d, unsigned 32 = %u, signed 64 = %ld\n", sint, uint, slong);
}
[steven#sexy:~]% ./test
signed 32 = -1, unsigned 32 = 1, signed 64 = 1
Notice how you can avoid this problem either by using an "unsigned" int (allowing the use of all 32 bits), or by going to a larger type which you don't overflow.
In your case, the 1 in your expression is a signed type - so when you upshift it by 31, its sign changes. Then downshifting causes the sign bit to be duplicated, and you end up with a bit pattern of 0xffffffff.
You can fix it like this:
int temp = (1UL << 31) >> 31;
GCC warns about this kind of error if you have -Wall turned on.
int is signed.
what 'problem' - what are you trying to do ?
int i = (1<<31); // i = -2147483648
i>>31; // i = -1
unsigned int i = (1<<31); // i = 2147483648
i>>31; // i = 1
ps ch is a nice command line 'c' intepreter for windows that lets you try this sort of stuff without compiling, it also gives you a unix command shell. See http://www.drdobbs.com/184402054
When you do (1<<31), the MSB which is the sign-bit is set(becomes 1). Then when you do the right shift, it is sign extended. Hence, you get -1. Solution: (1UL << 31) >> 31.
bit to indicate the sign is set when you do "such" left shift on a integer variable. Hence the result.

Resources