Какие преобразования типов происходят? - PullRequest
1 голос
/ 23 сентября 2010
#include "stdio.h"

int main()
{
    int x = -13701;
    unsigned int y = 3;
    signed short z = x / y;

    printf("z = %d\n", z);

    return 0;
}

Я ожидаю, что ответ будет -4567.Я получаю "z = 17278".Почему повышение этих номеров приводит к 17278?

Я выполнил это в Code Pad .

Ответы [ 4 ]

10 голосов
/ 23 сентября 2010

Скрытые преобразования типов:

signed short z = (signed short) (((unsigned int) x) / y);

Когда вы смешиваете подписанный и неподписанный типы, выигрывают беззнаковые.x преобразуется в unsigned int, деленное на 3, и затем этот результат преобразуется с понижением до (со знаком) short.С 32-разрядными целыми числами:

(unsigned) -13701         == (unsigned) 0xFFFFCA7B // Bit pattern
(unsigned) 0xFFFFCA7B     == (unsigned) 4294953595 // Re-interpret as unsigned
(unsigned) 4294953595 / 3 == (unsigned) 1431651198 // Divide by 3
(unsigned) 1431651198     == (unsigned) 0x5555437E // Bit pattern of that result
(short) 0x5555437E        == (short) 0x437E        // Strip high 16 bits
(short) 0x437E            == (short) 17278         // Re-interpret as short

Кстати, ключевое слово signed не нужно.signed short это более длинный способ сказать short.Единственный тип, который нуждается в явном signed, это char.char может быть подписан или не подписан в зависимости от платформы;все остальные типы всегда подписаны по умолчанию.

4 голосов
/ 23 сентября 2010

Краткий ответ: дивизия сначала повышает x до unsigned.Только тогда результат возвращается к signed short.

Длинный ответ: прочитайте этот поток SO.

3 голосов
/ 23 сентября 2010

Проблема исходит от unsigned int y. Действительно, x/y становится неподписанным. Работает с:

#include "stdio.h"

int main()
{
    int x = -13701;
    signed int y = 3;
    signed short z = x / y;

    printf("z = %d\n", z);

    return 0;
}
1 голос
/ 23 сентября 2010

Каждый раз, когда вы смешиваете «большие» значения со знаком и без знака в аддитивных и мультипликативных арифметических операциях, «выигрывает» тип без знака, и оценка выполняется в области типа без знака («большой» означает int и более). Если исходное значение со знаком было отрицательным, оно сначала будет преобразовано в положительное значение без знака в соответствии с правилами преобразования со знаком в без знака. В вашем случае -13701 превратится в UINT_MAX + 1 - 13701, а результат будет использован в качестве дивиденда.

Обратите внимание, что в результате преобразования со знаком в без знака на типичной 32-битной платформе int будет получено значение без знака 4294953595. После деления на 3 вы получите 1431651198. Это значение слишком велико, чтобы его можно было принудительно ввести в объект short на платформе с 16-разрядным типом short. Попытка сделать это приводит к поведению, определяемому реализацией. Таким образом, если свойства вашей платформы такие же, как в моих предположениях, то ваш код вызывает поведение, определяемое реализацией. Формально говоря, «бессмысленное» значение 17278, которое вы получаете, является не чем иным, как конкретным проявлением этого поведения, определенного реализацией. Возможно, что если вы скомпилируете свой код с включенной проверкой переполнения (если ваш компилятор их поддерживает), он будет задержан на назначении.

...