Неожиданное приведение типов между значениями в C - PullRequest
0 голосов
/ 27 июня 2019

У меня есть фрагмент кода C

unsigned int x = 0xDEADBEEF;
unsigned short y = 0xFFFF;
signed int z = -1;
if (x > (signed short) y)
    printf("Hello");
if (x > z)
    printf("World");

Я хотел бы знать, оценивает ли сравнение в первом утверждении

DEADBEEF > FFFFFFFF

Правильно ли я предположить, что y, который был unsigned short, сначала явно приведен к signed short. Битовое представление остается прежним. Тогда для сравнения y интерпретируется как расширенное целое число знака, поэтому оно становится FFFFFFFF из FFFF.

Кроме того, может ли базовое представление битов изменяться при явном приведении? Как распространить малые типы по сравнению с большими? У short всего 2 байта, а у int 4. Я в замешательстве!

Ответы [ 2 ]

4 голосов
/ 27 июня 2019

C 2018 6.5.4 5 сообщает нам, что оператор приведения в x > (signed short) y выполняет преобразование:

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

6.3.1.3 сообщает нам о конверсиях. Результат зависит от того, может ли значение в y, 0xFFFF (то есть 65535) быть представлено в signed short. Стандарт C требует signed short для представления до 32767, но это может быть и больше. Если это так, то параграф 1 говорит нам, что результат имеет то же значение. В противном случае пункт 3 гласит:

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

Таким образом, если signed short равно 16 битам, то (signed short) y имеет значение, определенное реализацией, или сигнал повышается.

Во многих реализациях C результат будет -1. Это значение signed short автоматически повышается до int (из-за обычных целочисленных повышений в 6.3.1.1 1), а x > (signed short) y фактически равно x > -1. В этот момент спецификация оператора > в 6.5.8 3 говорит нам (со ссылкой на обычные арифметические преобразования в 6.3.1.8) int преобразуется в unsigned int для соответствия x. Преобразование выполняется в соответствии с 6.3.1.3 2:

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

Это приводит к преобразованию -1 в UINT_MAX-1, и выражение фактически равно 0xDEADBEEF > UINT_MAX-1, что неверно, поскольку UINT_MAX равно по крайней мере 0xFFFFFFFF.

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

Нет, битовое представление не обязательно должно оставаться прежним.

Кроме того, может ли базовое представление битов изменяться при явном приведении?

Да. Приведения в C во многом определяются тем, как они влияют на значение . Они не определены как реинтерпретация битов исходного значения или, как правило, для сохранения битов исходного значения.

Как расширить маленькие типы по сравнению с большими?

Существует три варианта преобразования более узкого целого числа в более широкое целое:

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

Когда результат имеет то же значение:

  • Для натуральных чисел результирующее значение представляется дополнительными нулевыми битами.
  • Для отрицательных целых чисел результирующее значение представляется дополнительными однобитными, если используется дополнение двух. Тем не менее, стандарт C допускает представления дополнения и знака и величины, поэтому эзотерические или древние реализации C, использующие их, будут производить любые битовые комбинации, необходимые для представления требуемого значения.
0 голосов
/ 27 июня 2019

Результат приведения определен реализацией.

6.3.1.3 [Целые числа со знаком и без знака]
1 Когда значение с целочисленным типом преобразуется в другой целочисленный тип, отличный от _Bool [....]
3 В противном случае новый тип подписывается и значение не может быть представлено в нем; либо результат определяется реализацией, либо определяется сигнал реализации.

...