Проблема 64-битного сдвига - PullRequest
3 голосов
/ 22 июня 2009

Почему этот код не записывает 0 как последний элемент, а 18446744073709551615? (скомпилировано с g ++)

#include <iostream>

using namespace std;
int main(){
    unsigned long long x = (unsigned long long) (-1);
    for(int i=0; i <= 64; i++)
        cout << i << " " << (x >> i) << endl;
    cout << (x >> 64) << endl;
    return 0;
}

Ответы [ 9 ]

13 голосов
/ 22 июня 2009

Когда вы сдвигаете значение на большее количество битов, чем размер слова, оно обычно сдвигается на mod word-size. По сути, сдвиг на 64 означает сдвиг на 0 битов, что равно смещению вообще. Вы не должны полагаться на это, поскольку это не определено стандартом и может отличаться на разных архитектурах.

7 голосов
/ 22 июня 2009

Сдвиг числа на число битов, равное или превышающее его ширину, является неопределенным поведением. Вы можете только безопасно сдвинуть 64-разрядное целое число между 0 и 63 позициями.

3 голосов
/ 22 июня 2009

Это предупреждение от компилятора должно быть подсказкой:

"предупреждение: счетчик смещения вправо> = ширина типа"

Это приводит к неопределенному поведению:

http://sourcefrog.net/weblog/software/languages/C/bitshift.html

1 голос
/ 22 июня 2009

Вы переполняете смену. Если вы заметили, GCC даже предупреждает вас:

warning: right shift count >= width of type

Как получилось? Вы включаете 64 в качестве допустимого сдвига, который является неопределенным поведением от 0 до 64 - 65 номеров (в том числе 0). 0 - первый бит (очень похоже на массивы).

#include <iostream>

using namespace std;
int main(){
    unsigned long long x = (unsigned long long) (-1);
    for(int i=0; i < 64; i++)
        cout << i << " " << (x >> i) << endl;
    cout << (x >> 63) << endl;
    return 0;
}

Будет выдавать ожидаемый результат.

1 голос
/ 22 июня 2009

Я получаю:

test.c:8: warning: right shift count >= width of type

так, возможно, это неопределенное поведение?

1 голос
/ 22 июня 2009

ну, вы меняете слишком много раз. вы переходите от 0 до 64 включительно, что в общей сложности 65 раз. Вы обычно хотите:

for(int i=0; i < 64; i++)
    ....
0 голосов
/ 07 декабря 2015

Вы можете использовать:

static inline pack_t lshift_fix64(pack_t shiftee, short_idx_t shifter){ return (shiftee << shifter) & (-(shifter < 64)); } для такого трюка: (-(shifter < 64)) == 0xffff ffff ffff ffff, если shiftter <64, и <code>(-(shifter < 64)) == 0x0 в противном случае.

0 голосов
/ 11 октября 2015

Еще одна ловушка для неосторожных: я знаю, что это старая ветка, но я пришел сюда в поисках помощи. Меня поймали на 64-битной машине с использованием 1 & lt; & lt; k, когда я имел в виду 1L & lt; LT; & k; k; в этом случае компилятор не поможет: (

0 голосов
/ 22 июня 2009

Битовая комбинация -1 выглядит как 0xFFFFFFFFFFFFFFFF в шестнадцатеричном формате для 64-битных типов. Таким образом, если вы напечатаете ее как переменную без знака, вы увидите наибольшее значение, которое может содержать 64-разрядная переменная без знака, то есть 18446744073709551615.

При сдвиге битов нам все равно, что означает значение в этом случае, т.е. не имеет значения, если переменная подписана или без знака, она обрабатывается одинаково (в этом случае все биты сдвигаются на один шаг вправо) ).

...