Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > 64-разрядный сдвиг


Автор: ksili 5.5.2009, 09:33
Вот на такой код
Код

unsigned __int64 *arr_64;
int var;

....

arr_64[i] |= 1 << (var-1)*2;

Компилятор выдаёт warning:
Цитата

warning C4334: '<<' : result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)

то есть << - это получается 32-разрядный сдвиг? Т.е. сдвиг в 32-битной переменной. Однако мне надо сдвигать именно в 64 разрядах. Т.е. единица может попасть и в старшее двойное слово. А это не выполняется, т.к. нижеследующий код выводит ноль:

Код

    char count_str[20];
    unsigned __int64 sdf = 1 << 32;

    itoa(sdf, count_str, 10);

    cout << count_str;


Может есть оператор для 64-битного сдвига? Я в MSDN-е такого не нашёл.

Автор: Lazin 5.5.2009, 09:46
Код

unsigned __int64 sdf = 1ui64 << 32;

Автор: ksili 5.5.2009, 09:53
Lazin, а что такой префикс можно использовать? У меня компилятор не понял. 

Но я уже понял, что сдвигать надо тоже 64-битную переменную:
 
Код

arr_64[i] |= (unsigned __int64)1 << (var-1)*2;


Добавлено через 6 минут и 21 секунду
Цитата(Lazin @  5.5.2009,  13:46 Найти цитируемый пост)
1ui64 << 32


Цитата(ksili @  5.5.2009,  13:53 Найти цитируемый пост)
а что такой префикс можно использовать?

Что-то я сегодня туплю. Подумал, что это префикс lui (long unsigned int),  а на самом деле это постфикс ui64.  smile 

Спасибо.

Добавлено через 6 минут и 37 секунд
Цитата(Lazin @  5.5.2009,  13:46 Найти цитируемый пост)
1ui64 << 32


Цитата(ksili @  5.5.2009,  13:53 Найти цитируемый пост)
а что такой префикс можно использовать?

Что-то я сегодня туплю. Подумал, что это префикс lui (long unsigned int),  а на самом деле это постфикс ui64.  smile 

Спасибо.

Автор: Thunderbolt 8.5.2009, 15:31
Из статьи "http://www.viva64.com/art-1-1-1958348565.html".


5. Операции сдвига

Операции сдвига при невнимательном использовании могут принести много неприятностей во время перехода от 32-битной к 64-битной системе. Начнем с примера функции, выставляющей в переменной типа memsize, указанный вами бит в 1:
Код
ptrdiff_t SetBitN(ptrdiff_t value, unsigned bitNum) {
  ptrdiff_t mask = 1 << bitNum;
  return value | mask;
}


Приведенный код работоспособен на 32-битной архитектуре и позволяет выставлять биты с номерами от 0 до 31. После переноса программы на 64-битную платформу возникнет необходимость выставлять биты от 0 до 63. Как Вы думаете, какое значение вернет следующий вызов функции SetBitN(0, 32)? Если Вы думаете, что 0x100000000, то авторы рады, что не зря подготовили эту статью. Вы получите 0.

Обратите внимание, что "1" имеет тип int и при сдвиге на 32 позиции произойдет переполнение, как показано на рисунке 2.


user posted image
Рисунок 2. Вычисление выражения "ptrdiff_t mask = 1 << bitNum".

Для исправления кода необходимо сделать константу "1" того же типа, что и переменная mask.

Код
ptrdiff_t mask = ptrdiff_t(1) << bitNum;


или
Код
ptrdiff_t mask = CONST3264(1) << bitNum;


Еще один вопрос. Чему будет равен результат вызова неисправленной функции SetBitN(0, 31)? Правильный ответ 0xffffffff80000000. Результатом выражения 1 << 31 является отрицательное число -2147483648. Это число представляется в 64-битной целой переменной как 0xffffffff80000000. Следует помнить и учитывать эффекты сдвига значений различных типов.

....


www.Viva64.com

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)