Чтобы помочь вам увидеть, что происходит в вашем коде, я включил текст стандарта, который объясняет, как выполняются автоматические преобразования типов (для целых чисел), а также раздел о побитовом сдвиге, поскольку это работает немного по-другому.Затем я перебираю ваш код, чтобы увидеть, какие именно промежуточные типы существуют после каждой операции.
Соответствующие части стандарта
6.3.1.1 Булевы, символы и целые числа
Если int может представлять все значения исходного типа, значение преобразуется в int;в противном случае он конвертируется в беззнаковое целое.Они называются целочисленными акциями.Все остальные типы не изменяются целочисленными акциями.
6.3.1.8 Обычные арифметические преобразования
(я просто суммирую соответствующие части здесь.)
- Целочисленное продвижение выполнено.
- Если они оба подписаны или оба без знака, они оба преобразуются в больший тип.
- Если тип без знака больше, тип со знакомпреобразуется в тип без знака.
- Если тип со знаком может представлять все значения типа без знака, тип без знака преобразуется в тип со знаком.
- В противном случае они оба преобразуются втип без знака того же размера, что и тип со знаком.
(В основном, если у вас есть a OP b
, размер используемого типа будет наибольшим из int
, тип (a), типа (b), и он будет предпочитать типы, которые могут представлять все значения, представляемые типом (a) и типом (b). И, наконец, он предпочитает подписанные типы. В большинстве случаев это означает, что это будет int.)
6.5.7 Операции побитового сдвига
Результатом E1 << E2 является E1-сдвинутая влево позиция E2;освобожденные биты заполнены нулями.Если E1 имеет тип без знака, значение результата составляет $ E1 x 2 ^ {E2} $, уменьшенное по модулю на единицу больше максимального значения, представляемого в типе результата.Если E1 имеет тип со знаком и неотрицательное значение, а $ E1 x 2 ^ {E2} $ представимо в типе результата, то это итоговое значение;в противном случае поведение не определено. </li>
Как все это относится к вашему коду.
Сейчас я пропускаю первый пример, поскольку я нене знаю, какой тип pop () возвращает.Если вы добавите эту информацию в свой вопрос, я могу обратиться и к этому примеру.
Давайте рассмотрим, что происходит в этом выражении (обратите внимание, что у вас было лишнее (
после первого приведения в вашей версии; яя удалил это):
(((int32_t)argument[0] << 8) & (int32_t)0x0000ff00 | (((int32_t)argument[1]) & (int32_t)0x000000ff) )
Некоторые из этих преобразований зависят от относительных размеров типов.Пусть INT_TYPE будет больше int32_t и int в вашей системе.
((int32_t)argument[0] << 8)
- Аргумент [0] явно приведен к int32_t
- 8 уже являетсяint, поэтому преобразование не происходит
- (int32_t) аргумент [0] преобразуется в INT_TYPE.
- Сдвиг влево происходит, и результат имеет тип INT_TYPE.
(Обратите внимание, что если бы аргумент [0] мог быть отрицательным, сдвиг был бы неопределенным поведением. Но так как он был изначально без знака, так что вы здесь в безопасности.)
Пусть a
представляет результат этихшаги.
a & (int32_t)0x0000ff00
- 0x000ff0 явно приведен к int32_t.
- Обычные арифметические преобразования.Обе стороны конвертируются в INT_TYPE.Результат имеет тип INT_TYPE.
Пусть b
представляет результат этих шагов.
(((int32_t)argument[1]) & (int32_t)0x000000ff)
- Оба явных приведения происходят
- Выполнены обычные арифметические преобразования.Обе стороны теперь INT_TYPE.
- Результат имеет тип INT_TYPE.
Пусть c
представляет этот результат.
b | c
- Обычные арифметические преобразования;без изменений, так как они оба INT_TYPE.
- Результат имеет тип INT_TYPE.
Заключение
Так что ни один из промежуточных результатов здесь не подписан.(Кроме того, большинство явных приведений были не нужны, особенно если в вашей системе sizeof(int) >= sizeof(int32_t)
).
Кроме того, поскольку вы начинаете с uint8_t
с, никогда не сдвигаете более 8 бит и сохраняете все промежуточные результаты в типах не менее 32 бит, верхние 16 бит всегда будут равны 0, а значениявсе они будут неотрицательными, что означает, что типы со знаком и без знака представляют все значения, которые вы могли бы иметь здесь точно такие же .
Что именно вы наблюдаете, что заставляет вас думать, что оно используетнеподписанные типы, где он должен использовать подписанные?Можем ли мы увидеть примеры входов и выходов вместе с ожидаемыми результатами?
Редактировать: Исходя из вашего комментария, получается, что причина, по которой он работает не так, как вы ожидали, не в том, что тип unsigned , но поскольку вы генерируете побитовые представления 16-битных знаковых целых, но сохраняете их в 32-битных знаковых целых.Избавьтесь от всех приведений, кроме (int32_t)argument[0]
(и измените их на (int)argument[0]
. int
- это обычно размер, на котором система работает наиболее эффективно, поэтому ваши операции должны использовать int, если у вас нет определенногопричина использовать другой размер).Затем приведите final result к int16_t
.