Заставляет ли функция unsigned int потерять биты? - PullRequest
0 голосов
/ 24 октября 2019

Мой вопрос очень похож на тот, который здесь , за исключением того, что я работаю с C.

Я написал некоторый код для поворота целого без знака;то есть функция bitRotate() (код ниже).

Функция работает очень хорошо, когда вместо printf s и scanf s я непосредственно помещаю нужные литералы, напримерbitRotate(0xabcdef00,8); в основной функции.

Однако, когда я передаю x в качестве аргумента, как в следующем коде, abcdef00, который был получен от пользователя, x повреждается до ab000000. Я проверял и дважды проверял и отлаживал свой код несколько раз, и я почти уверен, что ошибка в этой части, но я не понимаю, почему.

#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;

}

Ответы [ 3 ]

0 голосов
/ 24 октября 2019

Ваш код имеет неопределенное поведение.

В этом вызове

scanf("%d", &n);

вы используете неправильный спецификатор преобразования с объектом типа char. Более того, тип char может вести себя как signed char или как unsigned char в зависимости от опции компилятора.

В функции используется неправильное выражение, когда n отрицательно

fallen >>= (WIDTH - n);
                 ^^^
fallen <<= (WIDTH - n);
                 ^^^

Я думаю, вы имеете в виду

fallen >>= (WIDTH + n);
                 ^^^
fallen <<= (WIDTH + n);
                 ^^^

В любом случае функция может быть написана проще. Вот демонстрационная программа.

#include <stdio.h>
#include <limits.h>

unsigned int bitRotate(unsigned int value, int n )
{
    const int Width = sizeof( unsigned int ) * CHAR_BIT;

    n %= Width;

    if ( n < 0 )
    {
        value = ( value >> -n ) | ( value << ( Width + n ) );
    }
    else if ( n > 0 )
    {
        value = ( value << n ) | ( value >> ( Width - n ) );

    }

    return value;
}

int main(void) 
{
    while ( 1 )
    {
        unsigned int x;

        printf( "Enter a hexadecimal value of x (0 - exit): " );

        if ( scanf( "%x", &x ) != 1 || x == 0 ) break;

        int n;

        printf( "Enter a negative or positive value of n (0 - exit): " );
        if ( scanf( "%d", &n ) != 1 || n == 0 ) break;

        printf( "\n%#x shifted %d is %#x\n", x, n, bitRotate( x, n ) );
    }

    return 0;
}

Вывод может выглядеть как

Enter a hexadecimal value of x (0 - exit): 0xabcdef00
Enter a negative or positive value of n (0 - exit): 16

0xabcdef00 shifted 16 is 0xef00abcd

Enter a hexadecimal value of x (0 - exit): 0xabcdef00
Enter a negative or positive value of n (0 - exit): -16

0xabcdef00 shifted -16 is 0xef00abcd

Enter a hexadecimal value of x (0 - exit): 0xabcdef00
Enter a negative or positive value of n (0 - exit): 32

0xabcdef00 shifted 16 is 0xabcdef00

Enter a hexadecimal value of x (0 - exit): 0
0 голосов
/ 24 октября 2019

Этот код показывает, имеет ли значение знаковый бит или нет:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const int arr[7] = {0x80000000u, -2, -1, 0, 1, 2, 0x7fffffffu};
    unsigned int i, j, signVal, uiSiz;

    uiSiz = sizeof(unsigned int);

    for (i = 0, j = 7; i < 7; i++) {
        signVal = ((unsigned int) arr[i] & (0x1u << ((8 * uiSiz) - 1))) >> ((8 * uiSiz) - 1);
        fprintf(stdout, "arr[%u]: %i, uiSiz: %u, signVal: %u;\n", i, arr[i], uiSiz, signVal);
    }

    return 0;
}

LINK @ [https://ideone.com/rWiSrF]

0 голосов
/ 24 октября 2019

Функция bitRotate в порядке, как и способ ее вызова.

Фактический виновник здесь:

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

Вы указали неверный спецификатор формата для scanfчто приводит к неопределенному поведению. Ваш компилятор, скорее всего, предупреждал вас об этом.

Спецификатору формата %d требуется указатель на int (который обычно занимает 32 бита), но вы предоставляете указатель на char, который занимает 8биты. Поэтому scanf, скорее всего, забивает память рядом с адресом n.

Вы хотите это:

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