简体   繁体   中英

right left shift bits in 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 × 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.

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 / 2 E2 . 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM