Операторы смены влево и вправо: <<>>

Побитовые операторы shift — это оператор shift вправо (>>), который перемещает биты целочисленного или перечисления выражения типа вправо, а оператор слева<< — влево, который перемещает биты влево. 1

Синтаксис

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

Замечания

Внимание

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

Сдвиги влево

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

В следующем примере показаны операции сдвига влево с использованием чисел без знака. В этом примере показано, что происходит с битами при представлении значения как 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;  // 0b00000000'00000100

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

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

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

#include <iostream>
#include <bitset>

using namespace std;

int main() {
    short short1 = 16384;
    bitset<16> bitset1(short1);
    cout << bitset1 << endl;  // 0b01000000'00000000

    short short3 = short1 << 1;
    bitset<16> bitset3(short3);  // 16384 left-shifted by 1 = -32768
    cout << bitset3 << endl;  // 0b10000000'00000000

    short short4 = short1 << 14;
    bitset<16> bitset4(short4);  // 4 left-shifted by 14 = 0
    cout << bitset4 << endl;  // 0b00000000'00000000
}

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

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

Внимание

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

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

#include <iostream>
#include <bitset>

using namespace std;

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

    unsigned short short12 = short11 >> 1;  // 512
    bitset<16> bitset12{short12};
    cout << bitset12 << endl;     // 0b00000010'00000000

    unsigned short short13 = short11 >> 10;  // 1
    bitset<16> bitset13{short13};
    cout << bitset13 << endl;     // 0b00000000'00000001

    unsigned short short14 = short11 >> 11;  // 0
    bitset<16> bitset14{short14};
    cout << bitset14 << endl;     // 0b00000000'00000000
}

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

#include <iostream>
#include <bitset>

using namespace std;

int main() {
    short short1 = 1024;
    bitset<16> bitset1(short1);
    cout << bitset1 << endl;     // 0b00000100'00000000

    short short2 = short1 >> 1;  // 512
    bitset<16> bitset2(short2);
    cout << bitset2 << endl;     // 0b00000010'00000000

    short short3 = short1 >> 11;  // 0
    bitset<16> bitset3(short3);
    cout << bitset3 << endl;     // 0b00000000'00000000
}

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

#include <iostream>
#include <bitset>

using namespace std;

int main() {
    short neg1 = -16;
    bitset<16> bn1(neg1);
    cout << bn1 << endl;  // 0b11111111'11110000

    short neg2 = neg1 >> 1; // -8
    bitset<16> bn2(neg2);
    cout << bn2 << endl;  // 0b11111111'11111000

    short neg3 = neg1 >> 2; // -4
    bitset<16> bn3(neg3);
    cout << bn3 << endl;  // 0b11111111'11111100

    short neg4 = neg1 >> 4; // -1
    bitset<16> bn4(neg4);
    cout << bn4 << endl;  // 0b11111111'11111111

    short neg5 = neg1 >> 5; // -1
    bitset<16> bn5(neg5);
    cout << bn5 << endl;  // 0b11111111'11111111
}

Смены и рекламные акции

Выражения с обеих сторон оператора сдвига должны быть целочисленными типами. Целочисленные рекламные акции выполняются в соответствии с правилами, описанными в разделе "Стандартные преобразования". Тип результата совпадает с типом повышенного 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 Если значение равно 0, операция смены не выполняется additive-expression .

#include <iostream>
#include <bitset>

using namespace std;

int main() {
    unsigned int int1 = 4;
    bitset<32> b1{int1};
    cout << b1 << endl;    // 0b00000000'00000000'00000000'00000100

    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;    // 0b00000000'00000000'00000000'00000100 (no change)
}

Сноски

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

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

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

См. также

Выражения с двоичными операторами
Встроенные операторы C++, приоритет и ассоциативность