Как работает целочисленное продвижение на C Cast? - PullRequest
0 голосов
/ 24 сентября 2018

Меня укусило неожиданное целочисленное повышение, и я удивился. Является ли согласованным в разных компиляторах, происходит ли повышение до явного приведения?

Позвольте мне объяснить.Имея 8-битную переменную со знаком, такую ​​как

int8_t s8a = -128; //<-- 0x80

Присвоение беззнаковому 16 как uint16_t s16b = s8a + 1; Я бы ожидал повышения до целого числа 0xFF81, тогда назначенного, это обычнаяпроисходит неправильно и рассматривается в таких документах, как MISRA C. Но явное приведение к типу без знака таким образом, как uint16_t s16b = (uint16_t)s8a Я бы ожидал, что s8a немедленно потеряет свою "подпись", а затем простирается с нуля до 16 бит, чтобы дать 0x0080 но на самом деле происходит обратное, так как он получает расширенный знак , а затем теряет свою подпись при приведении и назначении, давая 0xFF80.

Является ли это поведение стандартным или другим неопределенным поведением C?

Ответы [ 2 ]

0 голосов
/ 24 сентября 2018

С учетом инициализации int8_t s8a = -128;:

  1. В случае инициализации uint16_t s16b = s8a + 1;:
    1. В выражении s8a + 1 значение в s8a ((int8_t)-128) повышается до (int)-128 и добавляется с (int)1 для получения (int)-127.
    2. При инициализации uint16_t s16b = (int)-127; (int)-127 преобразуется в (uint16_t)0xff81 и сохраняется в s16b.
  2. В случае инициализации uint16_t s16b = (uint16_t)s8a + 1;:
    1. В выражении (uint16_t)s8a значение в s8a ((int8_t)-128) преобразуется в(uint16_t)0xff80.
    2. В выражении (uint16_t)0xff80 + 1:
      • Если INT_MAX >= 65535, то (uint16_t)0xff80 преобразуется в (int)0xff80 и добавляется с (int)1 для получения (int)0xff81.
      • Если INT_MAX < 65535, то 1 преобразуется в (uint16_t)1 и добавляется с (uint16_t)0xff80 для получения (uint16_t)0xff81.
    3. В инициализации uint16_t s16b = (int)0xff81; (когда INT_MAX >= 65535) или инициализация uint16_t s16b = (uint16_t)0xff81; (когда INT_MAX < 65535):
      • Если INT_MAX >= 65535, то (int)0xff81 преобразуется в (uint16_t)0xff81 и сохраняется в s16b.
      • Если INT_MAX < 65535, то (uint16_t)0xff81 сохраняется в s16b.

В обоих случаях s16b инициализируется значением (uint16_t)0xff81.

0 голосов
/ 24 сентября 2018

Это связано не с целочисленным продвижением, а с преобразованием типов.В вашем случае процесс хорошо определен стандартом C11 - 6.3.1.3 Целые числа со знаком и без знака (p2) :

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

Так что здесь 0xFF80 = 0xFFFF + (-128) + 1, как 0xFFFF - это максимум, который может быть представлен в uint16_t.

...