Какова причина нечетного поведения побитового оператора в следующем коде? - PullRequest
2 голосов
/ 27 марта 2012

В моем приложении на C # есть метод, который пытается упаковать целое число, но оператор сдвига ведет себя странно.
Комментарии в приведенном ниже коде показывают содержимое кода, видимое отладчиком после выполнения строки.

        long code = 0;          //0x0000000000000000
        code += (0x1111 << 32); //0x0000000000001111
        code += (0x2222 << 16); //0x0000000022221111
        code += (0x3333);       //0x0000000022224444

Возьмем первую строку, я ожидаю, что код, содержащийся в скобках, будет выполнен первым, что приведет к смещению 0x1111 влево на 32 бита, но это не так, но на следующей строке это смещение действительно имеет место и также в правильном месте (т. е. перед добавлением необходимо сместить 0x2222, иначе результат будет 0x33330000).

Что я упустил из-за оператора, который это объясняет?

Ответы [ 2 ]

6 голосов
/ 27 марта 2012

Что вы пропустили, так это то, что операции по сдвигу битов в строках являются модом 32. Поскольку 0x1111 - это int, операция - 0x1111 << (32 % 32), то есть 0x1111 << 0, то есть просто 0x1111.

Что вы, вероятно, хотите, это 0x1111L << 32.

Из раздела 7.9 спецификации C #:

  • Когда тип x равен int или uint, счет сдвига задается младшими пятью битами count. Другими словами, число сдвигов вычисляется из count & 0x1F.

  • Когда тип x равен long или ulong, счет сдвига задается младшими шестью битами count. Другими словами, число сдвигов вычисляется из count & 0x3F.

На некоторых аппаратных архитектурах смещение int на 32 даст 0, в то время как на других архитектурах будет то же самое int. Чтобы иметь согласованное поведение, разработчики C # должны были выбрать один из этих вариантов. Текущее поведение просто требует выполнения & 0x1F для счетчика сдвигов на архитектурах, которые в противном случае дают 0. Однако всегда возвращение 0 потребует сравнения и ветвления на архитектурах, которые дают int. Поскольку филиалы, как правило, дороги, имеет смысл выбрать наиболее быстрый вариант в большинстве случаев.

1 голос
/ 27 марта 2012

Я верю, потому что 0x1111 рассматривается как int.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...