Установить самый старший бит в C

Я пытаюсь установить самый старший бит в long long unsigned, x. Для этого я использую эту строку кода:

x |= 1<<((sizeof(x)*8)-1);

Я думал, что это должно работать, потому что sizeof задает размер в байтах, поэтому я умножился на 8 и вычитал один, чтобы установить последний бит. Всякий раз, когда я это делаю, компилятор имеет это предупреждение: "предупреждение: количество сдвигов влево >= ширина типа"

Я не понимаю, почему эта ошибка возникает.

Ответ 1

Перемещаемый 1 - это константа типа int, что означает, что вы смещаете значение int на биты sizeof(unsigned long long) * 8) - 1. Этот сдвиг может быть легко больше, чем ширина int, что, по-видимому, произошло в вашем случае.

Если вы хотите получить некоторую маску маски-маски типа unsigned long long, вы должны начать с начальной битовой маски типа unsigned long long, а не типа int.

1ull << (sizeof(x) * CHAR_BIT) - 1

Возможно, лучший способ создать ту же маску -

~(-1ull >> 1)

или

~(~0ull >> 1)

Ответ 2

используют 1ULL < вместо 1 <

Используя только "1", вы перемещаете целое число. 1ULL будет беззнаковым длинным, что вам нужно. Целое число будет, вероятно, 32 бита и long long, вероятно, 64 бита в ширину. Итак, смещение:

1 << ((sizeof(long long)*8)-1)

будет (скорее всего):

1 << 63

Так как 1 - это целое число, которое (скорее всего) 32 бита, вы получаете предупреждение, потому что вы пытаетесь перейти от MSB 32-битного значения.

Ответ 3

Литерал 1, который вы меняете, не является автоматически unsigned long long (но int) и, следовательно, не имеет столько бит, сколько вам нужно. Закрепите его с помощью ULL (т.е. 1ULL) или переведите его на unsigned long long перед тем, как сдвинуть его, чтобы сделать его правильным.

Кроме того, чтобы быть более безопасным для странных платформ, замените 8 на CHAR_BIT. Обратите внимание, что это по-прежнему не всегда лучший способ установить самый старший бит, см., Например, этот вопрос для альтернатив.

Вы также должны рассмотреть возможность использования такого типа, как uint64_t, если вы предполагаете unsigned long long быть определенной шириной или uint_fast64_t/uint_least64_t, если вам нужна хотя бы определенная ширина, или uintmax_t если вам нужен самый большой доступный тип.

Ответ 4

Благодаря 2-символьному представлению отрицательных целых чисел наиболее отрицательным интергером является именно желаемая битовая диаграмма только с набором MSB. Поэтому x |= (unsigned long long )LONG_LONG_MIN; тоже должен работать.