2010-03-08 4 views
20

Кажется, что я должен иметь возможность выполнять сдвиг бит в C/C++ более чем на 32 бита, если левый операнд сдвига длинный. Но это, похоже, не работает, по крайней мере, с компилятором g ++.Как бить сдвиг длиннее на 32 бита?

Пример:

unsigned long A = (1L << 37) 

дает

A = 0 

, который не то, что я хочу. Я что-то упустил или это просто невозможно?

-J

+2

Long 32 бита на большинстве архитектур .... –

+0

Используйте 'LL' вместо того, чтобы просто' L' –

ответ

11

Re-попробовать это с помощью переменной типа uint64_t (от stdint.h) вместо long. uint64_t гарантированно будет длиной 64 бит и должен вести себя так, как вы ожидали.

+4

Если 'long' равно 32 битам, то' (1L << 37) 'будет равно нулю независимо от типа переменной. '1' должен быть добавлен к типу назначения. – Potatoswatter

+7

@Potatoswatter: если 'long' - 32 бита, то поведение ** не определено ** для сдвигов в 32 бит или более. Фактически, на GCC/x86, '1L << 37 == 32'. То же самое для GCC/PowerPC. (То, что происходит, означает, что сдвиг просто получает пять бит). –

+1

@ Dietrich: True. Моя точка зрения (которую я также, по-видимому, не упомянул) заключается в том, что выражение, которое он, вероятно, хотел, было «1LL << 37». – Potatoswatter

9

Ну, это зависит от фактического размера типа long (точнее, его ширина в битах). Скорее всего, на вашей платформе long имеет ширину 32 бит, поэтому в результате вы получите 0 (также см. Ниже P.S.). Используйте больший тип. long long может быть?

P.S. В качестве дополнительного примечания, сдвиг типа на большее количество бит, чем его ширина (или равное количество бит), вызывает неопределенное поведение в C и C++ (C++ использует термин длина вместо ширина). Таким образом, вы не гарантированно получить 0 ни от 1L << 37 ни 1L << 32 на платформе, где long имеет ширину 32.

+0

Право, обоснование будет то, что в некоторых процессорах инструкция сдвига будет смотреть только на низких бит и компилятору C разрешено дублировать это поведение.Итак, (i << 37) на 32-битном int может быть таким же, как (i << 5). Курс «неопределенное поведение» означает, что он может делать абсолютно все, но это, вероятно, будет другим «наблюдаемым» поведением, кроме возвращения 0. –

+0

@Ben Voigt: Точно. Более того, это один из примеров UB, который на самом деле проявляется на практике. На таком оборудовании часто можно заметить, что, например, 'int i = 5; i << = 37; 'произвел другой результат из' int i = (5 << 37); ', поскольку первый был рассчитан CPU во время выполнения, а второй - компилятором во время компиляции. – AnT

26

A равно 0, поскольку А имеет только 32 бита, поэтому, конечно, вы смещаются все биты от слева оставляя только 0 бит влево. Вы должны сделать 64-битную:

unsigned long long A = (1ULL << 37); 

Или, если вы собираетесь использовать Visual C++:

unsigned __int64 A = (1ULL << 37); 
+0

Я предполагаю, что я привык к Java, где долго гарантировано 64 бит. Если это всего лишь 32 бита, то как он отличается от int? – 2010-03-08 20:28:50

+3

Чтобы сделать вещи немного яснее, я хотел бы кое-что прояснить. Размеры C-типов char, short, int, long, long long варьируются в зависимости от архитектуры и компилятора. Тем не менее, стандарт C гарантирует это соотношение: sizeof (char) <= sizeof (short) <= sizeof (int) <= sizeof (long) <= sizeof (long long) Но для типичных 32-битных машин , возможно, это то, что вы компилируете, размеры для char, short, int, long и long long равны соответственно 8, 16, 32, 32 и 64 бит. – Cthutu

+5

Педантичное замечание: стандарт C не гарантирует этого. C++ стандарт делает. Стандарт C говорит, что 'диапазон char <= диапазон коротких <= диапазон int <= диапазон длинного <= диапазон длинного длинного", но он ничего не говорит о 'sizeof'. Формально отношения для 'sizeof' могут не выполняться на C, хотя это было бы очень странно и экзотично. – AnT

2

Вы уверены, что длинный бит 64 бит с вашей конкретной ОС и компилятором? Используйте stdint.h и попробовать, как это:

#include <stdint.h> 

uint64_t x = (1ULL << 37); 
0

Новый Стандарт C++ вводит LL и Улла суффиксы для целочисленных литералов. Вы можете попытаться использовать их, поскольку все последние компиляторы поддерживают их. Но вы должны знать, что он не является частью текущего стандарта C++.

long long A = (1LL << 37) 
0

В вашем случае вы ограничены языковыми типами. Общее решение для [квази] произвольных размерных чисел использует класс Integer под номером Crypto++.

-1

У вас есть аргументы в обратном порядке.

unsigned long A1 = (1L << 37); // is 2 to the 37th 
unsigned long A = (37UL<<1UL); // has just multiplied 37 by 2 
+0

Почему вы думаете, что они хотят 37 * 2? Нет ни малейшего намека на то, что это была цель в вопросе. – ShadowRanger

Смежные вопросы