2015-07-31 2 views
3

Я немного смущен, потому что хотел инициализировать переменную типа unsigned long, размер которой составляет 8 байтов в моей системе (на каждой современной системе, я полагаю). Когда я хочу назначить переменную 1 << 63, я получаю предупреждение о компиляторе, и число на самом деле равно 0. Когда я делаю 1 << 30, я получаю ожидаемый результат от 2^30 = 1073741824. Но когда я делаю 1 << 31, я получаю результат 2^64 (думаю, на самом деле это не должно быть возможным), который печатает 18446744071562067968.бит смещение с unsigned long type производит неправильные результаты

Может ли кто-нибудь объяснить это поведение мне?

+5

пытались ли вы '1UL << 63' –

+0

Нет, никогда не видел это обозначение (я довольно новыми для C), спасибо :) – borchero

+1

@OliverBorchert Вы можете использовать суффиксы номер с' 'U' для знака 'и' L' для 'long', чтобы изменить тип этого литерала. Есть еще некоторые суффиксы, посмотрите в C-книгу для более подробной информации. – fuz

ответ

8

1 << 63 будет вычисляться в int арифметике, а ваш int, вероятно, 32 бит.

Устраните это, продвигая один из аргументов: 1ULL << 63 сделает это.

ULL означает, что выражение будет не менее 64 бит.

+0

Да, хорошо, спасибо, я приму ответ, как только это возможно – borchero

+0

Фактически 'UL' не 64 бит в длину на 32-битных архитектурах, 'ULL' есть. – dwalter

+1

Nitpicking, но если он не был изменен в более новом стандарте, чем тот, который у меня есть, unsigned long не гарантируется более чем на 32 бит, так как ULONG_MAX не гарантируется более чем 4294967295. –

2

Выражение 1 << 63 имеет тип int. Диапазон int составляет -2 ... 2 - 1 на большинстве систем, 2 слишком большой для этого. Попробуйте либо (unsigned long)1 << 63, либо 1UL << 63, чтобы сдвинуть значение типа unsigned long, оставив на 63 места.

1

1 здесь, целочисленная константа. По нормам, указанным в стандарте, C11, глава §6.4.4.1 синтаксис то же

целочисленная константа:
          десятичный константа целое суффикса неавтоматического
          восьмиугольная константа целочисленный суффикс opt
            шестнадцатеричного-константа целочисленного суффикса неавтоматического

и относительно семантика,

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

и таблица говорит, если нет суффикса, а значение представимо в int диапазоне следует рассматривать как int. Итак, 1 здесь, считается int, который составляет обычно 4 байта, или 32 бита, также то же самое в вашем случае.

Чтобы явно указать бит 1 в unsigned long (64), мы можем использовать суффикс, как

1UL << 63 

должно решить проблему.

Обращаем ваше внимание, что unsigned long не может быть 64 бит. Ожидается, что у unsigned long long должно быть не менее 64 бит. Тем не менее, до тех пор, пока вы используете платформу, где unsigned long на 64 бит, вы должны быть хорошо

+0

'unsigned long long' не может быть равно 64 битам, это может быть 128 бит или что-то в этом роде. – fuz

+0

@FUZxxl Это _at наименьшее 64 бит. Я могу переместить 128-битную переменную (-ы) в 64-битные места без каких-либо проблем, в другом случае. :-) –

+0

Я просто хотел указать, что 'unsigned long long' может быть не ровно 64 бита (это всего лишь * не менее * 64 бит), ваш ответ указывает на обратное. – fuz

2

Я рекомендую вам использовать 1ULL, поскольку это даст вам 64-разрядное целое число без знака на 32 и 64-битной архитектуры , На 32-битной архитектуре unsigned long (и поэтому UL) составляет всего 32 бит и не решит проблему.

1ULL << 63 
+1

Имейте в виду, что 'unsigned long long' - это тип, который недоступен на платформах C89. – fuz