Подписанный сдвиг вправо: какой компилятор использует логический сдвиг

Я тестировал правую смену с Visual Studio, Ubuntu GCC, компилятором Intel, MinGW. Все изменения в знаке бит. Я думаю, Xcode GCC делает то же самое.

Я знаю, что поведение специфично для реализации, но похоже, что все основные компиляторы рабочего стола/сервера реализуют арифметический сдвиг. Есть ли широко используемый компилятор, который не сдвигает бит знака?

Спасибо.

Ответ 1

C работает на множестве разных архитектур. Я имею в виду много разных архитектур. Вы можете получить код C на встроенном DSP и на суперкомпьютере Cray.

Большинство "определенных реализацией" частей стандарта C, которые люди воспринимают как нечто само собой разумеющееся, действительно делают перерыв на неясных архитектурах. Например, есть DSP и суперкомпьютеры Cray, где CHAR_BIT - это что-то огромное, например 32 или 64. Поэтому, если вы попробуете свой код на x86, и, возможно, если вы щедрые PowerPC, ARM или SPARC, вы вряд ли столкнется с каким-либо из действительно странных случаев. И это хорошо. Большинство кодов в эти дни всегда будут работать в байт-ориентированной архитектуре с целыми числами с двумя дополнениями и арифметическими сдвигами. Я не сомневаюсь, что любые новые архитектуры процессоров в обозримом будущем будут такими же.

Но рассмотрим два наиболее распространенных представления для целых чисел: twos-дополнение и дополнения:

switch ((-1) >> 1) {
case 0:
case -0:
    puts("Hello, one complement world!");
    // Possibly sign-magnitude.
    break;
case -1:
    puts("Hello, two complement world!");
    break;
default:
    puts("Hello, computer without arithmetic shift");
    break;
}

Не потейте. Просто придерживайтесь /, когда хотите разделить, и >>, когда вам нужно сдвинуть. Даже плохие компиляторы хорошо оптимизируют эти операции. (И помните, что x/2 != x>>1, если x отрицательный, если вы не используете одну машину дополнения, что почти наверняка не соответствует действительности.)

Стандарт гарантирует, что если (int) x не является отрицательным, то (int) x >> n == (unsigned) x >> n, поэтому компилятор не может сделать что-то совершенно неожиданное.

Ответ 2

Как правило, это больше зависит от целевой архитектуры, используемой компилятором. Если арка имеет как арифметические (подписанные), так и логические (беззнаковые) инструкции сдвига, то компиляторы C для этой арки будут использовать то, что подходит. С другой стороны, если он имеет только логические сдвиги, компилятор C будет использовать это, даже если он не "делает правильную вещь" для отрицательных значений, поскольку спецификация C позволяет компилятору что-либо делать.

Ответ 3

Cray C-компилятор делает логический сдвиг по значению по умолчанию по умолчанию, но вместо этого существует возможность делать арифметический сдвиг.

Как правило, можно с уверенностью предположить, что подписанный сдвиг вправо является арифметическим.

Ответ 4

Насколько я могу судить, оператор → выполняет арифметический сдвиг. Однако существует разница между тем, как выполняется сдвиг для подписанных и беззнаковых целых чисел - будет расширять MSB (который обычно является битом знака), а unsigned не будет (они всегда неотрицательны, так что бит знака всегда равен нулю).

РЕДАКТИРОВАТЬ: применять "обычно" ко всему, что я написал выше;).