Почему я не могу хранить 2 ^ 64 в unsigned long на 64-битной машине? - PullRequest
0 голосов
/ 16 мая 2018

Я что-то упустил?Я запустил следующее:

$ uname -a
Linux archlinux 4.16.6-1-ARCH #1 SMP PREEMPT Mon Apr 30 12:30:03 UTC 2018 x86_64 GNU/Linux

Затем в программе на C:

long l;
printf("sizeof long: %d\n", sizeof l);

, который выдает:

sizeof long: 8

Не означает ли это, что каждый длинныйсодержит 64 бита?Но когда я выполняю следующую строку кода:

printf("2^64: %ld\n",  1UL<<64);

я получаю следующее предупреждение от gcc:

sizeof.c: 14: 29: предупреждение: счетчик сдвига влево>= ширина типа [-Wshift-count-overflow]

Если вместо этого уменьшить левое смещение до 63, предупреждение исчезает, но выводится:

2 ^ 64: -9223372036854775808

Это наводит меня на мысль, что мое предположение о беззнаковом длинном из 64 используемых битов неверно, но почему?

Ответы [ 2 ]

0 голосов
/ 17 мая 2018

sizeof действительно вернет вам количество байтов, так что да, он имеет 64 бита. С помощью N двоичных цифр вы можете представлять 2^N числа. Если ваша переменная без знака, это означает [0, (2^N)-1] диапазон. Если это число со знаком, то диапазон будет [-2^(N-1), +2^(N-1)-1]. Если вы хотите узнать больше о знаковых целых числах, вы можете прочитать «Дополнение к двум».

Переходя к отображению целого числа: вы говорите printf, как интерпретировать переменную. Если вы скажете, что это целое число со знаком, тогда он будет использовать самый значимый бит в качестве знака вместо значения 2^63 (опять же, обратите внимание на дополнение к двум).

Это, с другой стороны, выведет целое число без знака:

printf("%lu", x);
0 голосов
/ 16 мая 2018

Число 2 ^ 64 требует 65 бит для правильного представления в двоичном формате - бит # 65 установлен, а остальные равны нулю.

Это та же самая причина, по которой 8-разрядные числа без знака могут доходить только до 255 (2 ^ 8 - 1), 16-разрядные числа без знака могут доходить только до 65535 (2 ^ 16 - 1),и т. д.

...