Странное поведение побитового NOT (~)
Как объяснить следующее поведение?
#include<iostream>
using namespace std;
int main(){
unsigned char a = 8;
cerr << "a: " << (int)a << '\n';
unsigned char b = (~a) >> 6;
cerr << "b: " << (int)b << '\n';
unsigned char c = (~a);
c = c >> 6;
cerr << "c: " << (int)c << '\n';
return 0;
}
Вывод:
a: 8
b: 255
c: 3
После дальнейшего тестирования кажется, что (~a)
становится int
, а не unsigned char
. Вот почему 1
получает смещение.
Что происходит?
EDIT: Мой компилятор является стандартным gcc 4.1.2
Ответы
Ответ 1
Все арифметические и побитовые операторы в C всегда расширяют свои аргументы, по крайней мере, до int
, если они были изначально более короткими интегральными типами. Это то, как определяется язык. Спецификация языка называет это "интегральной рекламой".
(Основная причина этого заключается в том, чтобы упростить реализацию C на архитектурах, где аппаратное обеспечение не поддерживает эффективные операции в более коротких количествах, чем полное машинное слово. Конечно, это также частично потому, что оно всегда срабатывало таким образом и не может быть изменен без нарушения существующего кода, который зависит от этого поведения).
Ответ 2
~a = 0xFFFFFFF7
, поэтому b = (~a) >> 6
приводит к b = 0xFF
; В случае с имеем c = (~a);
, приводящее к c = 0xF7
, поэтому c>>6
будет 3. Henning Makholm объясняет целочисленное продвижение хорошо выше. Это статья также полезна.
Ответ 3
a = 8
~a = -9 (int)
~a >> 6 = -1 (int)
(unsigned char)-1 = 255