简体   繁体   中英

Logical right shift in C with ~0 value

I have a very simple code, in which logical shift works with ~0 value in strange way

As I know its related to the signed/unsigned data types

#include <stdio.h>

void printfbits(int x) {
    for (int i=7; i>=0;i--) {
        printf("%d", x>>i & 1);
    }
    printf("\n");
}

int main() {
    printfbits(~0>>1); 
}

I expect 0111111, not 1111111. I also tried, no success

printfbits(((unsigned int)~0)>>1);

On most platforms, int is 32 bits or 64 bits long. Therefore, you are shifting more than 8 bits to the right, which leaves you with more than 8 bits enabled:

11...11111111 >> 1

becomes:

11...11111111 // if sign extension happens
01...11111111 // if not

As you see, regardless of whether sign extension happens or not, you will still see all 1 s since you only print the lower 8 bits.

Right shift of negative signed values is implementation defined . For gcc, a 1 is shifted in, otherwise a 0 is shifted in.

You were on the right track with the cast, but it doesn't help since the function still expects an int . You need to change the function to take an unsigned char and you have to mask out all but the lowest byte before performing the shift in the function call.

#include <stdio.h>

void printfbits(unsigned char x) {
    for (int i=7; i>=0;i--) {
        printf("%d", x>>i & 1);
    }
    printf("\n");
}

int main() {
    printfbits((~0u & 0xff)>>1);
}

Also, note the use of the U suffix on the constant 0. That gives the constant a type of unsigned int .

The negation in ~0 will happen with type int . But even if you do ~(unsigned char)0 , it'll still happen with type int because of implicit promotions. Consequently, you'll get extra more 1-bits on the left (int is usually 32 bits large (must be at least 16)). You can strip them by casting the bitnegation result to uint8_t .

I'd also recommend doing bit ops on unsigned s ( 0 u rather than 0 ) as the semantics are better standardized for those.

#include <stdio.h>
#include <stdint.h>

void printfbits(int x) {
    for (int i=7; i>=0;i--) {
        printf("%d", x>>i & 1);
    }
    printf("\n");
}

int main() {
    printfbits( (uint8_t)~0u >>1 );  //prints 01111111
}

It is signed shift which is implementation defined. But on most 2 complement machines:

在此输入图像描述

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