2016-12-30 2 views
-6

Я узнал о 2's Complement и неподписанных и подписанных int. Поэтому я решил проверить свои знания, насколько я знаю, что отрицательное число хранится в 2's complement так, чтобы сложение и вычитание не имели бы другого алгоритма и схемы были бы простыми.Как в сборке присваивается отрицательное число неподписанной работе int?

Теперь, если я пишу

int main() 
{ 
    int a = -1 ; 
    unsigned int b = - 1 ; 

    printf("%d %u \n %d %u" , a ,a , b, b); 
} 

Выходной Comes To Be -1 4294967295 -1 4294967295. Теперь я посмотрел на схему битов и различные вещи, а затем понял, что -1 в дополнении 2: 11111111 11111111 11111111 11111111, поэтому, когда я интерпретирую его с использованием% d, он дает -1, но когда я интерпретирую с использованием %u, он обрабатывает его как положительное число и поэтому он дает 4294967295. Я проверил, скопище код

.LC0: 
    .string "%d %u \n %d %u" 
main: 
    push rbp 
    mov  rbp, rsp 
    sub  rsp, 16 
    mov  DWORD PTR [rbp-4], -1 
    mov  DWORD PTR [rbp-8], -1 
    mov  esi, DWORD PTR [rbp-8] 
    mov  ecx, DWORD PTR [rbp-8] 
    mov  edx, DWORD PTR [rbp-4] 
    mov  eax, DWORD PTR [rbp-4] 
    mov  r8d, esi 
    mov  esi, eax 
    mov  edi, OFFSET FLAT:.LC0 
    mov  eax, 0 
    call printf 
    mov  eax, 0 
    leave 
    ret 

Теперь здесь -1 перемещается в регистр оба раза в беззнаковое и знаковое. То, что я хочу знать, если реинтерпретация только имеет значение, то почему у нас есть два типа: unsigned и signed, это printf формат строки %d и %u, что имеет значение?

Дальше, что действительно происходит, когда я назначаю отрицательное число целому числу без знака (я узнал, что инициализатор преобразует это значение из int в unsigned int.), Но в коде сборки я не видел такой вещи. Так что же происходит на самом деле?

И как машина знает, когда она должна делать 2's complement, а когда нет, она видит отрицательный знак и выполняет 2's complement?

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

+3

* «Как машина знает, когда он должен сделать 2 в дополнение, а когда нет» * - Я не понимаю, это - все сводится к тому, двоичная в программировании. Машинные инструкции не заботятся о 'signed' или' unsigned', это конструкции более высокого уровня. – UnholySheep

+0

@UnholySheep Что я имею в виду, когда я пишу подписанный int a = -1, он хранится как дополнение к 2, поэтому каждое отрицательное число не имеет значения, где оно хранится таким образом или нет? –

+1

Для языка C отрицательное число может быть одним из трех представлений, поэтому необязательно дополнение 2. Также формат printf должен соответствовать вводу, или ваша программа плохо сформирована. Текущий стандарт C поддерживает дополнение 2 таким образом, что преобразование типов подписей в и из неподписанных типов не изменяет представление битов на компьютере с дополнительным дополнением 2. Машины действительно не знают о значении переменной, когда она находится в регистре. Компилятор знает, поэтому программа знает, и этого достаточно. – user3528438

ответ

2

Оба подписанных и неподписанных являются фрагментами памяти, и в соответствии с операциями важно, как они себя ведут.

Это не имеет никакого значения при добавлении или вычитании из-за того, что из-за 2-дополнения операции точно такие же.

Это имеет значение, когда мы сравниваем два числа: -1 меньше 0, а 4294967295 - нет.

О преобразовании - для того же размера он просто принимает переменное содержимое и перемещает его в другое - так 4294967295 становится -1. Для большего размера он сначала подписан расширенным, а затем содержимое перемещается.

Как работает машина - согласно инструкции, которую мы используем. Машины имеют либо разные инструкции для сравнения подписанных и неподписанных, либо предоставляют разные флаги для него (x86 имеет перенос для неподписанного переполнения и переполнение для переполнения подписей).

Кроме того, обратите внимание, что C расслаблен, как хранятся подписанные числа, они не должны быть 2-дополнениями. Но в настоящее время все распространенные архитектуры хранят подписанные таким образом.

+0

, когда я присваиваю -1 неподписанному int, что происходит, в сборке он показывает то же самое для подписанных и unsigned int. –

+4

@SurajJain это потому, что в представлении дополнения 2 значения * являются * одинаковыми. Это один и тот же двоичный бит. Это то, как они * используются *, что делает их разными. –

+0

@WeatherVane То, что я прошу, является каждым отрицательным числом, представляется как дополнение 2, а также, если я храню отрицательное число в unsigned int http://stackoverflow.com/a/7152835/5473170, он записывает инициализатор, преобразует это значение из int к неподписанному int. Где это происходит? –

0

Есть несколько различий между подписанных и неподписанных типов:

  1. Поведение операторов <, <=, >, >=, /, % и >> все разные при работе с подписанных и неподписанных номера.

  2. Компиляторы не обязаны вести себя предсказуемо, если любое вычисление по значению знака превышает диапазон его типа. Даже при использовании операторов, которые будут вести себя одинаково со значениями со знаком и без знака во всех определенных случаях, некоторые компиляторы будут вести себя «интересным» способом. Например, компилятор, заданный x+1 > y, может заменить его x>=y, если x подписан, но нет, если x не имеет знака.

Как более интересный пример, в системе, где «короткая» составляет 16 бит и «INT» 32 бита, компилятор заданной функции:

unsigned mul(unsigned short x, unsigned short y) { return x*y; } 

можно предположить, что не ситуация может когда возникает, когда продукт будет превышать 2147483647. Например, если он видел, функция вызывается как unsigned x = mul(y,65535); и y был unsigned short, он может опустить код в другом месте, что было бы актуально, если только y были больше, чем 37268.

+0

Можем ли мы поговорить сэр? –

+0

@SurajJain: Конечно. Дайте мне знать, где. – supercat

-1

Выбор знакового целочисленного представления остается на платформе. Представление применяется как к отрицательным, так и к неотрицательным значениям, например, если 11012 (-5) является дополнением двух от 01012 (5), то 01012 (5) равно также дополнение 2 11012 (-5).

Платформа может или не может содержать отдельные инструкции для операций с целыми числами с подписью и без знака. Например, x86 предоставляет различные команды умножения и деления для подписанных (и imul) и целых чисел без знака (div и mul), но использует то же самое дополнение (add) и вычитание (sub) для обоих.

Аналогичным образом, x86 предоставляет команду сравнения (cmp) для целых чисел с подписью и без знака.

Арифметические и сравнительные операции будут устанавливать один или несколько флагов регистров состояния (перенос, переполнение, ноль и т. Д.). Они могут использоваться по-разному, когда речь идет о словах, которые должны представлять подписанные значения vs. unsigned.

Насколько printf обеспокоен, вы абсолютно правильно, что спецификатор преобразования определяет битовый шаблон 0xFFFF ли отображается в -1 или 4294967295, хотя помните, что если тип аргумента не совпадает с тем, что спецификатор преобразования ожидает, то поведение не определено. Использование %u для отображения отрицательного signed int может или не может дать ожидаемое эквивалентное значение без знака.

+0

Что подразумевается под инициализатором, меняет тип int на неподписанный тип, когда это происходит? –

+0

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

0

Кажется, что вы пропустили факты, которые, во-первых, 0101 = 5 как в знаках целого числа, так и без знака, а во-вторых, вы присвоили отрицательное число неподписанному int - то, что ваш компилятор может быть достаточно умным, чтобы реализовать и , поправьте на подписанный int.

Установка неподписанных Int -5 должна технически вызвать ошибку, потому что без знака Интс не может хранить значения под 0.

0

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

see this blog post for assembly level explanation.

Смежные вопросы