Расширение знака без знака long long - PullRequest
5 голосов
/ 26 сентября 2011

Мы нашли несколько странных значений, маленький тестовый пример ниже.Это печатает "FFFFFFFFF9A64C2A".Значение неподписанного длинного длинного, кажется, было расширенным знаком.Но почему ?Все перечисленные ниже типы не подписаны, так что же делает расширение знака?Ожидаемый результат будет "F9A64C2A".

#include <stdio.h>

int main(int argc,char *argv[])
{
    unsigned char a[] = {42,76,166,249};

    unsigned long long ts;
    ts = a[0] | a[1] << 8U | a[2] << 16U | a[3] << 24U;

    printf("%llX\n",ts);


    return 0;

}

Ответы [ 3 ]

5 голосов
/ 26 сентября 2011

В выражении a[3] << 24U a[1] имеет тип unsigned char.Теперь "целочисленное продвижение" преобразует его в int, потому что:

В выражении можно использовать следующее, где можно использовать int или unsigned int:

[...]

Если int может представлять все значения исходного типа, значение преобразуется в int;в противном случае он конвертируется в unsigned int.

( (черновик) ISO / IEC 9899: 1999 , 6.3.1.1 2)

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

Тип результата - тип повышенного левого операнда.

(6.5.7 3)

На 32-битной платформе,249 << 24 = 4177526784 интерпретируется как int с установленным битом знака.

Простое изменение на

ts = a[0] | a[1] << 8 | a[2] << 16 | (unsigned)a[3] << 24;

устраняет проблему (суффикс U для констант не оказывает влияния).

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

Некоторые из сдвинутых a [i], когда они автоматически преобразуются из unsigned char в int, дают значения с расширенным знаком.

Это согласуется с разделом 6.3.1 Арифметические операнды, подраздел 6.3.1.1 Булевы, символы и целые числа, из проекта стандарта C N1570, который частично читается как «2. Следующее может использоваться в выражении везде, где int или unsigned int могут использоваться: ... - Объект или выражение с целочисленным типом (кроме int или unsigned int) чей целочисленный конверсионный ранг меньше или равен рангу int и unsigned int. ... Если int может представлять все значения исходного типа ..., значение преобразуется в int; в противном случае он конвертируется в беззнаковое целое. Они называются целочисленными акциями. ... 3. Целочисленные акции сохраняют значение, включая знак. "

См., Например, www.open-std.org / JTC1 / SC22 / WG14 / www / docs / n1570.pdf

Вы можете использовать код, подобный следующему, который работает нормально:

      int i;
      for (i=3, ts=0; i>=0; --i) ts = (ts<<8) | a[i];
1 голос
/ 26 сентября 2011
 ts = ((unsigned long long)a[0]) | 
    ((unsigned long long)a[1] << 8U) | 
    ((unsigned long long)a[2] << 16U) | 
    ((unsigned long long)a[3] << 24U); 

Приведение запрещает преобразование промежуточных результатов в тип int по умолчанию.

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