Почему побайтовый сдвиг даёт разные результаты?
Читайте тут до прояснения раздел "Bitwise shift operator.
Смысл в том, что если вы знаковое число сдвинули влево так, что старшим разрядом стала 1, то в результате получится отрицательное число. При сдвиге вправо знакового числа, освобождающиеся слева разряды заполняются битом знака (а не нулем), поэтому результат сдвига отрицательного числа так же будет отрицательным (а положительного - положительным:). Если сдвигать вправо беззнаковое число, то свободные биты будут всегда заполнятся нулями.
Кстати, на сколько помню, по стандарту знаковость char не определена (может быть как знаковым так и беззнаковым). Вам с вашим примером не повезло, char оказался знаковым. Зато это дало возможность немного глубже понять сдвиги.
Привет от integer promotion. Поэтапно с типами:
#include <iostream>
using namespace std;

int main() {

    char index = 33;
    auto c1 = index << 2;
    auto c2 = c1 >> 2;
    cout << typeid(c1).name() << " " << c1 << endl;
    cout << typeid(c2).name() << " " << c2 << endl;

    char enc;
    enc = index << 2;
    cout << "enc: " << (int)enc << endl;
    enc = enc >> 2;
    cout << "enc: " << (int)enc << endl;

    return 0;
}

Почему 33 << 2 дало отрицательное число в signed char, думаю, не надо объяснять?