Побитовое смещение * на * отрицательное число для обращения битов в числе - PullRequest
0 голосов
/ 14 февраля 2019

Допустимо ли выполнять побитовый сдвиг на отрицательную величину?Например, если у меня есть следующий код:

#include <stdint.h>
uint32_t reverse_bits (uint32_t n)
{
    uint32_t result = 0;    
    for (int i = 0; i < 32; i++) 
    {
        uint32_t bit = n & (1 << i);
        bit <<= 31 - i * 2;
        result |= bit;
    }
    return result;
}

Это то, что я мог бы ожидать работать на всех архитектурах (в частности, что результат выражения x << shift_amt, где shift_amount < 0 true, эквивалентенна x >> -shift_amt)?

Примечание: Это , а не вопрос о поведении выполнения побитового сдвига для отрицательного числа (то есть -1 << 1).


Вот полная тестовая программа:

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
uint32_t reverse_bits (uint32_t n)
{
    uint32_t result = 0;
    for (int i = 0; i < 32; i++)
    {
        uint32_t bit = n & (1 << i);
        bit <<= 31 - i * 2;
        result |= bit;
    }
    return result;
}
void print_bits (uint32_t n)
{
    for (int i = 0; i < 32; i++)
        putchar(n & (1 << i) ? '1' : '0');
    putchar('\n');
}
int main ()
{
    for (int i = 0; i < 5; i++)
    {
        uint32_t x = rand();
        x |= rand() << 16;
        print_bits(x);
        print_bits(reverse_bits(x));
        putchar('\n');
    }
}

Ответы [ 2 ]

0 голосов
/ 14 февраля 2019

Как уже упоминалось, сдвиг на отрицательное значение вызывает неопределенное поведение согласно разделу 6.5.7p3 стандарта C .

Вместо попытки угадать, когдаВы можете избежать негативного сдвига, изменить код, так что вам не нужно.

После маскировки нужного бита, верните его в положение 0, , затем , сдвиньте егов нужное место.Кроме того, убедитесь, что вы изменили константу 1 на 1ul, чтобы в конечном итоге не сдвинуть значение со знаком в бит знака и не превысить ширину int.Обратите внимание также на использование sizeof, чтобы избежать жесткого кодирования магических чисел, таких как 32.

unsigned long reverse_bits (unsigned long n)
{
    unsigned long result = 0;
    for (int i = 0; i < sizeof(unsigned long) * CHAR_BIT; i++)
    {
        unsigned long bit = ((n & (1ul << i)) >> i);
        unsigned long shift = (sizeof(unsigned long) * CHAR_BIT) - i - 1;
        result |= bit << shift;
    }
    return result;
}
0 голосов
/ 14 февраля 2019

Стандарт C заявляет, что смещение на отрицательное число является явно неопределенным поведением в § 6.5.7 параграфа 3:

Если значение правого операнда отрицательно или больше или равно ширине повышенного левого операнда, поведение не определено.

Выделение мое.

...