Страницы

Поиск по вопросам

суббота, 14 декабря 2019 г.

Неверный результат побитового НЕ

#c #битовые_операции


Почему возникает ошибка при выводе результата унарной операции ~?
(должно было ведь получиться  ~a = 0)

#include 

int main (void)
{
    unsigned char a = 0xff;

    printf("a = %u\n", a);
    printf("~a = %u\n", ~a);

    return 0;
}


Результат (компилятор - Clang) :

a = 255
~a = 4294967040

    


Ответы

Ответ 1



Результат ~a имеет тип int, и вычисляется обращением битов после превращения a в int (integer promotions, так как int может представить все значения unsigned char, если не рассматривать редкий случай когда UCHAR_MAX > INT_MAX). В с11 (n1570): The result of the ~ operator is the bitwise complement of its (promoted) operand (that is, each bit in the result is set if and only if the corresponding bit in the converted operand is not set). The integer promotions are performed on the operand, and the result has the promoted type. If the promoted type is an unsigned type, the expression ~E is equivalent to the maximum value representable in that type minus E К примеру, на одной из возможных реализаций: (~a) -> ~(FF) -> ~(00 00 00 FF) -> FF FF FF 00 = -256 Затем %u интерпретирует int как unsigned int, поэтому для примера выше: printf() получает -256 (FF FF FF 00) и выводит 4294967040 (34 32 39...). 0 вы получите, если (~a) назад в unsigned char превратить: unsigned char b = ~a; в этом случае -256 в ноль превращается (§6.3.1.3/2) так как вычисления по модулю UCHAR_MAX+1 происходят (UCHAR_MAX=255 здесь). printf("%u", b) выведет 0. Аналогично, в случае с %hhu: printf() получает int (FF FF FF 00) и интерпретирует его как unsigned char для печати: #include int main(void) { unsigned char a = 0xff, b = ~a; printf("a=%d b=%d ~a=%d\n", a, b, ~a); printf("a=%u b=%u ~a=%u\n", a, b, ~a); printf("a=%hhu b=%hhu ~a=%hhu\n", a, b, ~a); } Результат a=255 b=0 ~a=-256 a=255 b=0 ~a=4294967040 a=255 b=0 ~a=0

Ответ 2



printf("~a = %u\n", ~a); %u говорит о том, что вы хотите вывести unsigned int. Так что вы получаете приведение к этому типу с последующей инверсией битов. Хотите получить 0? Тогда делайте так: unsigned int a = 0xffffffff; printf("a = %u\n", a); printf("~a = %u\n", ~a); Или, если нужен один байт - используйте верный префикс - %hhu: unsigned char a = 0xff; printf("a = %hhu\n", a); printf("~a = %hhu\n", ~a);

Комментариев нет:

Отправить комментарий