Правильное смещение целого числа на число бит, равное или большее, чем его размер, является неопределенным поведением.
С11 6.5.7 Битовые операторы сдвига
Синтаксис
shift-expression: additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
Ограничения
Каждый из операндов должен иметь целочисленный тип.
Семантика
целочисленных акции выполняется на каждом из операндов. Тип результата - это продвинутый левый операнд. Если значение правого операнда отрицательное или больше или равно ширине продвинутого левого операнда, поведение не определено.
Результат E1 << E2
is E1
левый сдвиг E2
битовые позиции; освобожденные биты заполняются нулями. Если E1
имеет неподписанный тип, то значение результата будет E1
× 2 E2, приведенное по модулю больше, чем максимальное значение, представляемое в типе результата.Если E1
имеет знак и неотрицательное значение, а E1
× 2 E2 представляется в виде результата, то это результирующее значение; в противном случае поведение не определено.
Результат E1 >> E2
: E1
Справа вправо E2
Битые позиции. Если E1
имеет неподписанный тип, или если E1 имеет подписанный тип и неотрицательное значение, значение результата является неотъемлемой частью отношения E1
/2 E2. Если E1
имеет подписанный тип и отрицательное значение, результирующее значение определяется реализацией.
Размер int
на вашей платформе, кажется, в большинстве 32 бит, так что инициализаторы для bit32R
и bit32L
имеют неопределенное поведение.
64-разрядные выражения должны быть записаны:
uint64_t bit32R = (uint64_t)code >> 32;
и
uint64_t bit32L = (uint64_t)code << 32;
Кроме того, форматы, используемые в printf
не являются правильными для аргументов, переданных (если int
не имеет 64 бита, которые будет производить различную продукцию).
Ваш компилятор, кажется, не полностью совместим с C99, вы должны добавить окончательный оператор return 0;
в конце тела функции main()
.
Вот исправленный вариант:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
int main(void) {
uint32_t code = 0xCDBAFFEE;
uint64_t bit32R = (uint64_t)code >> 32;
uint16_t bit16R = code >> 16;
uint8_t bit8R = code >> 8;
uint8_t bit0R = code >> 0;
uint64_t bit32L = (uint64_t)code << 32;
uint16_t bit16L = code << 16;
uint8_t bit8L = code << 8;
uint8_t bit0L = code << 0;
printf("Right shift:\n"
"bit32R %.16"PRIx64"\n"
"bit16R %"PRIx16"\n"
"bit8R %"PRIx8"\n"
"bit0R %"PRIx8"\n\n",
bit32R, bit16R, bit8R, bit0R);
printf("Left shift:\n"
"bit32L %.16"PRIx64"\n"
"bit16L %"PRIx16"\n"
"bit8L %"PRIx8"\n"
"bit0L %"PRIx8"\n\n",
bit32L, bit16L, bit8L, bit0L);
return 0;
}
Выход:
Right shift:
bit32R 0000000000000000
bit16R cdba
bit8R ff
bit0R ee
Left shift:
bit32L cdbaffee00000000
bit16L 0
bit8L 0
bit0L ee
это не может быть то, что вы ожидаете, потому что типы переменных несколько противоречивы.
Ваш код вызывает неопределенное поведение. Значение сдвига '32' слишком велико для 32-битного' int' (то же самое для 16 бит, если ваша платформа имеет 16 бит 'int'). И используйте макросы 'PRInX' из' inttypes.h' для печати типов фиксированной ширины. У вас есть мнение о том, как работают целые операции. – Olaf
Я сменил файл include на stdint! Что ничего не изменило, но я забыл о stdint и включил inttypes. Но я думаю, что они одинаковые, по крайней мере для моего кода. –
Возможно, прежде чем делать предположения, полезно прочитать, что представляют заголовки, как они связаны и что означает «PRInX»? – Olaf