Caractere assinado e não assinado de comparação

Parece tão estranho. Eu encontrei um mal-entendido. Eu uso o gcc com char como char assinado. Eu sempre pensei que, nas expressões de comparação (e outras expressões), o valor assinado é convertido em não assinado, se necessário.

int a = -4;
unsigned int b = a;
std::cout << (b == a) << std::endl; // writes 1, Ok

mas o problema é que

char a = -4;
unsigned char b = a;
std::cout << (b == a) << std::endl; // writes 0

qual é a mágica no operador de comparação, se não for apenas bit a bit?