2013-09-17 5 views
5

у меня есть процедура маскирования (которая создает все-онов битовую маску для нижней части для заданного размера):Битовые маски и долго-долго

template<class T> 
T bottom_half() { 
    T halfway = ((sizeof(T) * 8)/2); 
    T mask = (1 << halfway) - 1; 

    return mask; 
} 

, который прекрасно работает, если я позвоню bottom_half<int>() или long или char. Но по какой-то причине, когда я запускаю его с long long, halfway правильно установлен на 32, но mask - 0. Почему это так?

+2

Правильное написание половины битов целого числа: 'std :: numeric_limits :: цифры/2'. Выражение, используемое выше, предполагает, что 'char' имеет 8 бит, что требуется (хотя я не знаю ни одной платформы, где это не 8 бит). –

+0

А, это интересно узнать, спасибо. – sircodesalot

+0

@ DietmarKühl: Я слышал, что Windows CE имеет байты с 16 бит в нем. – Nawaz

ответ

8

По умолчанию сдвиг влево сдвигается 1, что равно int по умолчанию и, вероятно, 32 бит на вашем компьютере. Когда вы меняете 1<<32, результат не определен, что означает, что он не предсказуем больше, поскольку это может быть что угодно.

На некоторых процессорах 1<<32 может привести к смещению бита с верхнего конца целого числа и в результате к 0. На других процессорах сдвиг 32 по модулю размера регистра, поэтому он эффективен с нулевым сдвигом, а результат равен 1. В любом случае он не определен.

(См. What's bad about shifting a 32-bit variable 32 bits? для обсуждения этого вопроса).

Заметим также, что sizeof возвращает блоки char или «байт» (они определены, чтобы быть такими же в С, sizeof(char) == 1 всегда), но С не гарантирует, что байт составляет 8 бит. Существует стандартный макрос CHAR_BIT, чтобы получить размер бита char.

Попробуйте

#include <limits.h> 

template<class T> 
T bottom_half() { 
    T halfway = ((sizeof(T) * CHAR_BIT)/2); 
    T mask = ((T)1 << halfway) - 1; 

    return mask; 
} 
+0

Отлично, спасибо! – sircodesalot

+0

Значит, вы имеете в виду '(1 << 32) - 1'' '0'? – Nawaz

+0

@dasblinkenlight: Как именно? – Nawaz

0

В ролях 1 в вашей операции сдвига для правильного типа. Как бы то ни было, это простое целое число, и поэтому сдвиг ничего не достигает - вы смещаете бит из существования.

3

Выражение 1 << x имеет тип int. Левое смещение знакового типа, так что значение превышает максимальное представляемое значение, имеет неопределенное поведение. Вместо этого используйте T(1) << x.

+0

+1. Это правильный ответ, так как он также говорит о * неопределенном поведении * в исходном коде. – Nawaz

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