C обычными арифметическими преобразованиями - PullRequest
9 голосов
/ 25 сентября 2011

Я читал в стандарте C99 об обычных арифметических преобразованиях.

Если оба операнда имеют одинаковый тип, дальнейшее преобразование не требуется.

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

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

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

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

Итак, допустим, у меня есть следующий код:

#include <stdio.h>

int main()
{
    unsigned int a = 10;
    signed int b = -5;

    printf("%d\n", a + b); /* 5 */
    printf("%u\n", a + b); /* 5 */
    return 0;
}

Я думал, что абзац с жирным шрифтом применим (так как unsigned int и signed int имеют одинаковый ранг.Почему b не преобразуется в unsigned?Или, может быть, он преобразован в неподписанный, но есть кое-что, чего я не понимаю?

Спасибо за ваше время: -)

Ответы [ 4 ]

6 голосов
/ 25 сентября 2011

Действительно b - , преобразованное в без знака.Однако то, что вы заметили, это то, что b, преобразованный в unsigned и затем добавленный к 10, дает значение 5.

На 32-битной архитектуре x86 это то, что происходитбез знака становится 4294967291 (то есть 2**32 - 5)

добавление 10 становится 5 из-за циклического перехода в 2**32 (2**32 - 5 + 10 = 2**32 + 5 = 5)
4 голосов
/ 25 сентября 2011

0x0000000a плюс 0xfffffffb всегда будет 0x00000005 независимо от того, имеете ли вы дело со знаковыми или беззнаковыми типами, если используется только 32 бита.

3 голосов
/ 25 сентября 2011

Повтор соответствующей части кода из вопроса:

unsigned int a = 10;
signed int b = -5;

printf("%d\n", a + b); /* 5 */
printf("%u\n", a + b); /* 5 */

В a + b, b преобразуется в unsigned int, (уступая UINT_MAX + 1 - 5 по правилу для unsigned to-подписанное преобразование).Результатом добавления 10 к этому значению является 5, по правилам арифметики без знака, а его тип - без знака int.В большинстве случаев тип выражения C не зависит от контекста, в котором оно появляется.(Обратите внимание, что все это не зависит от представления; преобразование и арифметика определяются исключительно в терминах числовых значений.)

Для второго вызова printf результат прост: "%u" ожидает аргументнапечатайте unsigned int, и вы дали ему один.Он печатает "5\n".

Первый printf немного сложнее."%d" ожидает аргумент типа int, но вы даете ему аргумент типа unsigned int.В большинстве случаев несоответствие типов, подобное этому, приводит к неопределенному поведению, но есть специальное правило, согласно которому соответствующие подписанные и неподписанные типы взаимозаменяемы в качестве аргументов функции - до тех пор, пока значение представимо в обоих типах (как здесь),Таким образом, первый printf также печатает "5\n".

Опять же, все это поведение определяется в терминах значений, а не представлений (за исключением требования, что данное значение имеет одинаковое представление в соответствующих знаковых и беззнаковыхтипов).Вы получите один и тот же результат в системе, где подписанные int и unsigned int имеют 37 бит, подписанный int имеет 7 битов заполнения, unsigned int имеет 11 битов заполнения, а подписанный int использует 1-е дополнение или знак-и-величинупредставление.(Насколько я знаю, в реальной жизни такой системы не существует.)

1 голос
/ 25 сентября 2011

Он преобразуется в unsigned, арифметика без знака просто дает результат, который вы видите. Результат беззнаковой арифметики эквивалентен выполнению знаковой арифметики с дополнением до двух без исключения вне диапазона.

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