В стандарте ISO C99 есть небольшой фрагмент, касающийся операторов битового сдвига:
shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
Целочисленные продвижения выполняются для каждого из операндов. Тип результата соответствует повышенному левому операнду. Если значение правого операнда отрицательное или больше или равно ширине расширенного левого операнда, поведение не определено.
Другими словами, как только вы начнете пытаться сдвинуть 64-битное (в вашей реализации) unsigned long
на 64 бита или более, все ставки будут сняты. Он может возвращать 0, исходное значение или 42. Он даже может форматировать ваш жесткий диск и отправлять порнографии вашему боссу (хотя я никогда не видел, чтобы реализация действительно делала это).
Вы можете обнаружить, что некоторые реализации (или даже базовое аппаратное обеспечение реализации) оптимизируют эти инструкции, эффективно используя только соответствующие биты. Другими словами, для 64-битного значения он вполне может использовать только младшие значащие семь бит (фактически and
с 0x3f
), чтобы дать вам операнд от 0 до 63.
В этом случае, поскольку 64 & 0x3f
равно нулю, это фактически не работает.
В любом случае, почему он ведет себя именно так, это предположение. Неопределенное поведение — это то, чего вам действительно следует избегать. Если вы действительно хотите, чтобы поведение работало так, как вы ожидаете, измените:
unsigned long const b = a >> shift_amount;
во что-то вроде:
unsigned long const b = (shift_amount < 64) ? a >> shift_amount : 0;
как показано в этом коде (64-битные значения в моей системе являются ULL):
#include <stdio.h>
#include <limits.h>
void rightshift_test(int const shift_amount) {
unsigned long long a = 0xabcd1234abcd1234ULL;
printf("a: %llx, shift_amount:%d: ", a, shift_amount);
unsigned long long const b = (shift_amount < 64) ? a >> shift_amount : 0;
printf("b: %llx\n", b);
}
int main() {
rightshift_test(56);
rightshift_test(60);
rightshift_test(61);
rightshift_test(62);
rightshift_test(63);
rightshift_test(64);
rightshift_test(99);
return 0;
}
Результат этого:
a: abcd1234abcd1234, shift_amount:56: b: ab
a: abcd1234abcd1234, shift_amount:60: b: a
a: abcd1234abcd1234, shift_amount:61: b: 5
a: abcd1234abcd1234, shift_amount:62: b: 2
a: abcd1234abcd1234, shift_amount:63: b: 1
a: abcd1234abcd1234, shift_amount:64: b: 0
a: abcd1234abcd1234, shift_amount:99: b: 0
person
paxdiablo
schedule
13.09.2012
0x3F
, потому что они смотрят только на младшие биты. Я не знаю, делает ли это x86-64, но, естественно, в результате>>64
имеет тот же эффект, что и>>0
. - person Steve Jessop   schedule 06.07.2012