2015-07-05 4 views
10

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

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

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

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

+2

Не используйте магические числа. Байт/'char' в C может иметь более 8 бит. Замените '8' на' CHAR_BIT'. – Olaf

ответ

12

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) 
+0

Мне нравятся эти новые способы, хотя они и не очевидны. – Artur

+0

Вверх проголосовали за хороший ответ, все еще можете рассказать о том, как '~ (-1ull >> 1)' или '~ (~ 0ull >> 1)' быть лучшим способом? –

+0

@ rakeb.void Поскольку он более компактен, он не зависит от 'CHAR_BIT' или других констант, и его легче читать (и меньше). –

7

использование 1ULL < < вместо 1 < <

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

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

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

1 << 63 

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

+0

@ Хуркил: действительно – Artur

+0

@ Тейлор: прочитайте [стандарт] (http://port70.net/~nsz/c/c11/n1570.html#6.5.7). – Olaf

+0

Целое число не является «скорее всего» 32 бит. Существует много архитектур с 16-битными целыми числами, некоторые с 24-битными целыми числами и т. Д. (Однако вы правы относительно UB). – Olaf

1

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

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

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

+0

И тогда вы все еще делаете предположения. Лучше рассчитать msb и установить его, если вы хотите быть портативным. – this

+0

@this Да, 'sizeof (type) * CHAR_BIT' - не лучшее решение, но по крайней мере он удаляет жестко закодированные' 8' из подхода OP. – Arkku

-1

Благодаря комплемента репрезентации 2'S отрицательных чисел, наиболее отрицательное interger точно желаемый битовый шаблон только с набором MSB. Так что x |= (unsigned long long)LONG_LONG_MIN; тоже должен работать.

+1

C не гарантирует фактически дополнение 2s, поэтому любая реализация, основанная на этом, будет в лучшем случае зависимой от реализации. – Olaf

Смежные вопросы