Search code examples
chexbit-shiftunsignedunsigned-integer

Does passing an unsigned int to a function make it lose bits?


My question is quite similar to the one here except that I’m working with C.

I wrote some code to rotate an unsigned int; that is, the function bitRotate() (code below).

The function works very well when, instead of the printfs and scanfs, I directly put the literals I want to use, e.g. bitRotate(0xabcdef00,8);in the main function.

However, when I pass x as an argument as in the following code, abcdef00 that was got from the user, the x gets corrupted to ab000000. I checked and double checked and debugged my code multiple times and I am pretty sure the error is in this part but I don’t understand why.

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define WIDTH sizeof(unsigned int)*CHAR_BIT

unsigned int bitRotate(unsigned int, char );

int main()
{

    unsigned int x;
    char n;
    while(1)
    {
        printf("Enter x: ");
        scanf("%x", &x);
        printf("Enter n: ");
        scanf("%d", &n);
        printf("%x\n", bitRotate(x,n));
    }

    return 0;
}

unsigned int bitRotate(unsigned int value, char n)
{

    char un = abs(n);
    unsigned int fallen = ~(0u);

    if(un == WIDTH)
        return value;
    else if (un < WIDTH)
    {

        if (n < 0)
        {
            fallen >>= (WIDTH - n);
            fallen = value & fallen;
            fallen <<= (WIDTH - n);
            value >>= n;
        }
        else
        {
            fallen <<= (WIDTH - n);
            fallen = value & fallen;
            fallen >>= (WIDTH - n);
            value <<= n;
        }
        value |= fallen;
        return value;

    }
    else
        return 0;

}

Solution

  • The bitRotate function is fine and so is the way you call it.

    The actual culprit is here:

    char n;
    scanf("%d", &n);  // <<<<<
    

    You provide the wrong format specifier to scanf which results in undefined behaviour. Your compiler most likely warned you about this.

    The %d format specifier needs an pointer to an int (which usually takes 32 bits), but you provide the pointer to a char which takes 8 bits. Therefore scanf most likely clobbers the memory adjacent to the address of n.

    You want this:

    int n;
    scanf("%d", &n);