Поделиться через


Операторы сдвигов влево и вправо (<< и >>)

Побитовые операторы сдвига являются оператором сдвига вправо (>>), который перемещает биты shift_expression вправо, и оператором сдвига влево (<<), перемещающим биты shift_expression влево. 1

shift-expression << additive-expression shift-expression >> additive-expression

Заметки

Важно!

Следующие описания и примеры распространяются на Windows для архитектур x86 и x64.Реализация операторов сдвига влево и сдвига вправо существенно отличается в Windows RT для устройств ARM.Дополнительные сведения см. в разделе "Операторы сдвига" публикации блога Hello ARM.

Сдвиги влево

Оператор сдвига влево вызывает сдвиг битов shift-expression влево на количество позиций, определенных с помощью additive-expression. Позиции битов, освобожденные при операции сдвига, заполняются нулями. Сдвиг влево является логическим сдвигом (биты, сдвигаемые с конца отбрасываются, включая бит знака). Дополнительные сведения о типах побитовых сдвигов см. в статье Bitwise shifts (Побитовые сдвиги).

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

#include <iostream>
#include <bitset>
using namespace std;

int main() {
    unsigned short short1 = 4;    
    bitset<16> bitset1{short1};   // the bitset representation of 4
    cout << bitset1 << endl;  // 0000000000000100

    unsigned short short2 = short1 << 1;     // 4 left-shifted by 1 = 8
    bitset<16> bitset2{short2};
    cout << bitset2 << endl;  // 0000000000001000

    unsigned short short3 = short1 << 2;     // 4 left-shifted by 2 = 16
    bitset<16> bitset3{short3};
    cout << bitset3 << endl;  // 0000000000010000
}

Если выполняется сдвиг влево числа со знаком и при этом затрагивается бит знака, результат не определен. В следующем примере показано, что происходит в Visual C++, если выполняется сдвиг влево 1 бита в позицию бита знака.

#include <iostream>
#include <bitset>
using namespace std;

int main() {
    short short1 = 16384;    
    bitset<16> bitset1{short2};
    cout << bitset1 << endl;  // 0100000000000000 

    short short3 = short1 << 1;
    bitset<16> bitset3{short3};  // 16384 left-shifted by 1 = -32768
    cout << bitset3 << endl;  // 100000000000000
 
    short short4 = short1 << 14;
    bitset<16> bitset4{short4};  // 4 left-shifted by 14 = 0
    cout << bitset4 << endl;  // 000000000000000  
}

Сдвиги вправо

Оператор сдвига вправо вызывает сдвиг группы битов shift-expression вправо на количество позиций, определенных с помощью additive-expression. Для чисел без знака позиции битов, освобожденные при операции сдвига, заполняются нулями. Для чисел со знаком бит знака используется для заполнения освобожденных позиций битов. Другими словами, если число является положительным, используется 0, если число является отрицательным, используется 1.

Важно!

Результат сдвига вправо отрицательного числа со знаком зависит от реализации.Хотя Visual C++ использует бит знака для заполнения освобожденных позиций битов, нет никакой гарантии, что другие реализации также выполняют это.

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

#include <iostream>
#include <bitset>
using namespace std;

int main() {
    unsigned short short11 = 1024;
    bitset<16> bitset11{short11};
    cout << bitset11 << endl;     // 0000010000000000

    unsigned short short12 = short11 >> 1;  // 512
    bitset<16> bitset12{short12};
    cout << bitset12 << endl;      // 0000010000000000

    unsigned short short13 = short11 >> 10;  // 1
    bitset<16> bitset13{short13};
    cout << bitset13 << endl;      // 0000000000000001

    nsigned short short14 = short11 >> 11;  // 0
    bitset<16> bitset14{short14};
    cout << bitset14 << endl;     // 0000000000000000}
}

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

#include <iostream>
#include <bitset>
using namespace std;

int main() {
    short short1 = 1024;
    bitset<16> bitset1{short1};
    cout << bitset1 << endl;     // 0000010000000000

    short short2 = short1 >> 1;  // 512
    bitset<16> bitset2{short2};
    cout << bitset2 << endl;      // 0000010000000000

    short short3 = short1 >> 11;  // 0
    bitset<16> bitset3{short3};   
    cout << bitset3 << endl;     // 0000000000000000
}

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

#include <iostream>
#include <bitset>
using namespace std;

int main() {
    short neg1 = -16;
    bitset<16> bn1{neg1};
    cout << bn1 << endl;  // 1111111111110000

    short neg2 = neg1 >> 1; // -8
    bitset<16> bn2{neg2};
    cout << bn2 << endl;  // 1111111111111000

    short neg3 = neg1 >> 2; // -4
    bitset<16> bn3{neg3};
    cout << bn3 << endl;  // 1111111111111100

    short neg4 = neg1 >> 4; // -1
    bitset<16> bn4{neg4};    
    cout << bn4 << endl;  // 1111111111111111

    short neg5 = neg1 >> 5; // -1 
    bitset<16> bn5{neg5};    
    cout << bn5 << endl;  // 1111111111111111
}

Сдвиги и перемещения

Выражения с обеих сторон оператора сдвига должны быть целочисленными типами. Восходящие приведения целого типа выполняются в соответствии с правилами, описанным в разделе Восходящие приведения целых типов. Тип результата соответствует типу приводимого shift-expression.

В следующем примере у переменной типа char уровень повышается до int.

#include <iostream>
#include <typeinfo>

using namespace std;

int main() {
    char char1 = 'a';

    auto promoted1 = char1 << 1;  // 194
    cout << typeid(promoted1).name() << endl;  // int

    auto promoted2 = char1 << 10;  // 99328
    cout << typeid(promoted2).name() << endl;   // int
}

Некоторые подробности

Результат операции сдвига не определен, если additive-expression имеет отрицательное значение или если additive-expression больше или равен количеству битов в повышаемом shift-expression. Операция сдвига не выполняется, если значение additive-expression равно 0.

#include <iostream>
#include <bitset>
using namespace std;

int main() {
    unsigned int int1 = 4;
    bitset<32> b1{int1};
    cout << b1 << endl;    // 00000000000000000000000000000100

    unsigned int int2 = int1 << -3;  // C4293: '<<' : shift count negative or too big, undefined behavior
    unsigned int int3 = int1 >> -3;  // C4293: '>>' : shift count negative or too big, undefined behavior

    unsigned int int4 = int1 << 32;  // C4293: '<<' : shift count negative or too big, undefined behavior

    unsigned int int5 = int1 >> 32;  // C4293: '>>' : shift count negative or too big, undefined behavior

    unsigned int int6 = int1 << 0;
    bitset<32> b6{int6};
    cout << b6 << endl;    // 00000000000000000000000000000100 (no change)}
}

Примечания

1 Ниже приводится описание операторов сдвига в спецификации C++ ISO (INCITS/ISO/IEC 14882-2011[2012]), разделы 5.8.2 и 5.8.3.

Значение E1 << E2 представляет собой E1 со сдвигом влево на E2 позиций битов; освобожденные биты заполняются нулями. Если E1 имеет тип без знака, значение результата будет равно E1 × 2E2, уменьшенное на остаток от деления значения, на единицу превышающего максимальное значение, которое можно представить в типе результата. В противном случае если E1 имеет тип со знаком и не отрицательное значение, а E1 × 2E2 можно представить в соответствующем типе без знака типа результата, это значение, преобразованное в тип результата, будет значением результата; в противном случае поведение не определено.

Значение E1 >> E2 представляет собой E1 со сдвигом вправо на E2 позиций битов. Если E1 имеет тип без знака или если E1 имеет тип со знаком и неотрицательное значение, значением результата будет целочисленная часть частного E1/2E2. Если E1 имеет тип со знаком и отрицательное значение, значение результата определяется реализацией.

См. также

Ссылки

Выражения с бинарными операторами

Операторы C++, приоритет и ассоциативность