c - это - тип byte си




как c компилятор обрабатывает unsigned и signed integer? Почему код сборки для беззнаковой и подписанной арифметической операции одинаковый? (4)

Я читаю книгу: CS-APPe2. C имеет неподписанный и подписанный тип int, и в большинстве архитектур использует двоичную арифметику для реализации знакового значения; но, изучив некоторый код сборки, я обнаружил, что очень мало инструкций различают неподписанные и подписанные. Поэтому мой вопрос:

  1. Является ли ответственность компилятора отличать подписанные и неподписанные? Если да, то как это делается?

  2. Кто реализует арифметику с двумя дополнениями - процессор или комплимент?

Добавить дополнительную информацию:

Изучив еще несколько инструкций, на самом деле некоторые из них различают подписанные и unsigned, такие как setg, seta и т. Д. Кроме того, CF и OF применяются к неподписанным и, соответственно. Но большинство целочисленных арифметических команд обрабатывают unsigned и подписывают то же самое, например

int s = a + b

а также

unsigned s = a + b

сгенерировать ту же инструкцию.

Итак, при выполнении ADD sd , если процессор обрабатывает s & d без знака или подписан? Или это не имеет значения, потому что бит-шаблон обоих результатов одинаковый, и задача компилятора - преобразовать результат базового битового шаблона в беззнаковый или подписанный?

PS Я использую x86 и gcc


Во многих случаях на уровне машины нет разницы между подписанными и неподписанными операциями, и это всего лишь вопрос интерпретации битовой диаграммы. Например, рассмотрим следующую 4-битную операцию слова:

Binary Add  Unsigned   2's comp
----------  --------   --------
  0011          3         3
+ 1011       + 11       - 5
-------     --------   --------
  1110         14        -2  
-------     --------   --------

Бинарный шаблон одинаковый для подписанной и неподписанной операции. Обратите внимание, что вычитание является просто добавлением отрицательного значения. Когда выполняется SUB-операция, правый операнд дополняется двумя (инвертирует биты и приращение), а затем добавляется (ответная цепь ALU является сумматором ); не на уровне инструкций, которые вы понимаете, но на логическом уровне, хотя можно было бы реализовать машину без инструкции SUB и все же выполнять вычитание, хотя и в двух инструкциях, а не в одном.

Существуют некоторые операции, которые требуют разных инструкций в зависимости от типа, и ответственность компилятора заключается в том, чтобы генерировать соответствующий код, вообще говоря, могут применяться архитектурные варианты.


Для большинства арифметических / логических операций нет необходимости различать подписанные и unsigned ints. Часто приходится принимать во внимание этот знак при печати, ноль / знак, расширяющий или сравнивающий значения. На самом деле CPU ничего не знает о типе значения. 4-байтовое значение представляет собой всего лишь несколько бит, оно не имеет никакого значения, если пользователь не указывает, что это float, массив из 4 символов, беззнаковый int или подписанный int и т. Д. Например, при печати переменной char , в зависимости от указанных свойств типа и вывода, он выдает символ, целое число без знака или целое число со знаком. Ответственность программиста заключается в том, чтобы показать компилятору, как обрабатывать это значение, а затем компилятор выдает правильную инструкцию, необходимую для обработки значения.


Это довольно легко. Операции, такие как сложение и вычитание, не нуждаются в корректировке для подписанных типов в арифметике дополнений двух. Просто выполните эксперимент разума и представьте себе алгоритм, используя только следующие математические операции:

  • увеличение на единицу
  • уменьшение на единицу
  • сравнивать с нулем

Дополнение просто берет предметы один за другим из одной кучи и помещает их в другую кучу до тех пор, пока первый не станет пустым. Вычитание берется у обоих из них сразу, пока вычитаемый не будет пустым. В модульной арифметике вы просто рассматриваете наименьшее значение как самое большое значение плюс одно, и оно работает. Дополнение Two - это просто модульная арифметика, где наименьшее значение отрицательно.

Если вы хотите увидеть какую-либо разницу, я рекомендую вам попробовать операции, которые небезопасны в отношении переполнения. Одним из примеров является сравнение ( a < b ).

Является ли обязанность ответственного за дифференцирование подписанных и неподписанных? Если да, то как это делается?

При необходимости генерируя разные сборки.

Кто реализует арифметику с двумя дополнениями - процессор или комплимент?

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

Это арифметические функции процессора, которые позволяют компилятору производить вычисления в двух дополнениях.

unsigned s = a + b

Обратите внимание, что способ plus вычисляется здесь, не зависит от типа результата. Insead зависит от типов переменных справа от знака равенства.

Итак, при выполнении ADD sd, если процессор обрабатывает s & d без знака или подписан?

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


Много было сказано о вашем первом вопросе, но мне нравится что-то сказать о вашем втором:

Кто реализует арифметику с двумя дополнениями - процессор или комплимент?

Стандарт C не требует, чтобы отрицательные числа имели два дополнения, он вообще не определяет, как аппаратные средства выражают отрицательные числа. Задача компилятора заключается в том, чтобы перевести код C в инструкции ЦП, которые выполняют то, что вы запрашиваете у своего кода. Таким образом, независимо от того, будет ли компилятор C создавать код для арифметики с двумя дополнениями или нет, это зависит только от того, использует ли ваш процессор арифметику с двумя дополнениями или нет. Компилятор должен знать, как работает ЦП и создает код соответственно. Поэтому правильный ответ на этот вопрос: CPU.

Если ваш процессор использовал представление с одним дополнением, чем компилятор C для этого ЦП, он выдал бы инструкции с одним дополнением. С другой стороны, компилятор C может эмулировать поддержку отрицательных чисел на процессоре, который вообще не знает отрицательных чисел. Поскольку двухкомпонентное дополнение позволяет вам игнорировать, если число подписано или не указано для многих операций, это не так сложно сделать. В этом случае это был бы компилятор, реализующий арифметику с двумя дополнениями. Это также может быть сделано на процессоре, который имеет представление для отрицательных чисел, но почему компилятор должен это сделать, а не просто использовать встроенную форму, которую понимает процессор? Таким образом, это не будет сделано, если только это не произойдет.





assembly