Почему смещение переменной более чем на ширину в битах обнуляется? - PullRequest
0 голосов
/ 03 июля 2018

Этот вопрос вдохновлен другими вопросами от StackOverflow. Сегодня, просматривая StackOverflow, я столкнулся с проблемой сдвига битов переменной на значение k, которое> = ширина этой переменной в битах. Это означает смещение 32-битного целого на 32 или более битовых позиций.

Сдвиг влево целого числа на 32 бита

Неожиданный результат C / C ++ операторов побитового сдвига

Из этих вопросов очевидно, что если мы попытаемся сдвинуть число на k битов, которые> = битовая ширина переменной, будут взяты только младшие значащие биты log2k. Для 32-разрядного типа int младшие 5 битов маскируются и принимаются за величину сдвига.

В общем, если w = ширина переменной в битах, x >> k становится x >> (k % w) Для int это x >> (k % 32).

Счет маскируется до пяти битов, что ограничивает диапазон счетчика от 0 до 31.

Итак, я написал небольшую небольшую программу для наблюдения за поведением, которое теоретически должно быть произведено. Я написал в комментариях итоговую величину сдвига% 32.

#include <stdio.h>
#include <stdlib.h>

#define PRINT_INT_HEX(x) printf("%s\t%#.8x\n", #x, x);

int main(void)
{
    printf("==============================\n");
    printf("Testing x << k, x >> k, where k >= w\n");

    int      lval = 0xFEDCBA98 << 32;
    //int      lval = 0xFEDCBA98 << 0;

    int      aval = 0xFEDCBA89 >> 36;
    //int      aval = 0xFEDCBA89 >> 4;

    unsigned uval = 0xFEDCBA89 >> 40;
    //unsigned uval = 0xFEDCBA89 >> 8;

    PRINT_INT_HEX(lval)
    PRINT_INT_HEX(aval)
    PRINT_INT_HEX(uval)

    putchar('\n');

    return EXIT_SUCCESS;
}

И вывод не соответствует ожидаемому поведению команд смены!

==============================
Testing x << k, x >> k, where k >= w
lval    00000000 
aval    00000000
uval    00000000

=============================================== ======================

На самом деле я был немного запутан с Java. В C / C ++ смещение int на число битов, превышающее ширину бит, может быть уменьшено на k% w, но это не гарантируется стандартом C. Нет правила, согласно которому такое поведение должно происходить постоянно. Это неопределенное поведение.

Однако в Java это так. Это правило языка программирования Java.

Описание операторов Bitshift в спецификации языка Java

Странный результат смещения целочисленного значения Java влево

java: расстояние сдвига для int ограничено 31 битом

Ответы [ 2 ]

0 голосов
/ 03 июля 2018

Одной из причин неопределенности является то, что 8086, исходный x86, не маскировал какие-либо биты за счет сдвига. Вместо этого он буквально выполнял смены, используя один такт для каждой позиции.

Затем Intel поняла, что допускать 255+ тактов для сменной инструкции, возможно, не очень хорошая идея. Например, они считали максимальное время ответа на прерывание.

Из моего старого руководства по 80286:

Чтобы уменьшить максимальное время выполнения, iAPX 286 не допускает, чтобы число сдвигов превышало 31. Если предпринимается попытка подсчета сдвигов, превышающего 31, используются только нижние пять битов отсчета сдвигов. IAPX 86 использует все 8 битов счетчика смен.

Это дало вам разные результаты для одной и той же программы на ПК / XT и ПК / АТ.

Так что же должен сказать языковой стандарт?

Java решила эту проблему, не используя базовое оборудование. Вместо этого С решил сказать, что эффект неясен.

0 голосов
/ 03 июля 2018

В связанных вопросах конкретно утверждается, что смещение на величину, превышающую ширину в битах смещаемого типа, вызывает неопределенное поведение , которое стандарт определяет как «поведение» при использовании непереносимой или ошибочной программной конструкции или ошибочных данных, к которым настоящий международный стандарт не предъявляет требований "

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

Стандарт C гласит следующее относительно операторов побитового сдвига в разделе 6.5.7p3:

Целочисленные продвижения выполняются для каждого из операндов. тип результата - тип повышенного левого операнда. Если значение правого операнда отрицательно или больше или равна ширине повышенного левого операнда, поведение не определено.

В этом случае вполне возможно, что компилятор может уменьшить величину смещения по модулю ширины в битах, как вы предложили, или он может обработать его как математическое смещение на эту величину, в результате чего все биты будут равны 0. Либо является допустимым результатом, потому что стандарт не определяет поведение.

...