在C语言中设置最高位

13

我想要在一个long long unsigned类型的变量x中设置最高位。 为了实现这个目标,我使用了下面这行代码:

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

我认为这应该可以工作,因为sizeof以字节为单位给出大小,所以乘以8并减去1可设置最终位。但每当我这样做时,编译器都会发出此警告:“warning: left shift count >= width of type”。

我不明白为什么会出现这个错误。


2
不要使用魔法数字。在C语言中,一个字节/char可以有超过8位。请用CHAR_BIT替换8 - too honest for this site
4个回答

17

你正在移位的 1 是一个 int 类型的常量,这意味着你正在将一个 int 值左移 sizeof(unsigned long long) * 8) - 1 比特位。这种移位可能超过了 int 的宽度,这显然就是你遇到的问题。

如果你想获取 unsigned long long 类型的某个位掩码 mask,你应该从一个 unsigned long long 类型的初始位掩码开始,而不是从一个 int 类型开始。

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

构建同样的口罩可能有一种更好的方式是

~(-1ull >> 1)
或者
~(~0ull >> 1)

我喜欢这些新方法,尽管它们不明显。 - Artur
对于一个好的答案已经点赞了,但您能否详细解释一下 ~(-1ull >> 1) 或者 ~(~0ull >> 1) 是为什么更好呢? - mazhar islam
@rakeb.void 因为它更紧凑,不依赖于CHAR_BIT或其他常量,并且更易于阅读(和更小)。 - Filipe Gonçalves
@rakeb.void: 这种方法“更好”是因为它具有较少的冗余。原始变量以两种方式取决于目标类型:字面后缀ull和移位距离sizeof(x) * CHAR_BIT。这种替代方法只有一个依赖关系-字面后缀。虽然乍一看不太明显,但程序员应该将其视为惯用法。 - AnT stands with Russia
为了避免依赖于字面后缀,请使用正确整数类型的表达式:~((x|~x)>>1)~(~(x^x)>>1),这两个表达式应该被任何自重编译器进行常量折叠。 (仅当x至少与int一样宽时才有效,但我认为在这种情况下这不是问题。) - rici
显示剩余3条评论

7

使用1ULL <<代替1 <<

只使用"1"会使您移位一个整数。1ULL将是一个无符号长整型,这正是您所需要的。 一个整数可能是32位,而long long可能是64位宽的。因此移位:

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

很可能会是:

1 << 63

由于1是一个整数,(很可能)是32位的,所以当你试图将其移动超过32位值的MSB时,会出现警告。


一个整数不一定是“最有可能”的32位。有许多架构使用16位整数,一些使用24位整数等等(但您关于UB的观点是正确的)。 - too honest for this site
@Olaf:是的,我知道 - int 的大小不仅取决于架构,还取决于编译器。同一 CPU 可以有两个不同的编译器,其 int 大小也不同。这里有许多微妙之处。 - Artur

1
你要移位的字面量1并不自动成为unsigned long long(而是int),因此它没有你需要的那么多位。在后缀中加上ULL (即1ULL),或在移位之前将其转换为unsigned long long以使其成为正确的类型。
另外,为了更安全地适应奇怪的平台,请将8替换为CHAR_BIT。请注意,这仍然不一定是设置最高有效位的最佳方法,例如,可以参考this question中的其他方法。
如果你假设unsigned long long是某个宽度,则还应该考虑使用uint64_t等类型,如果你需要至少某个宽度,则应该使用uint_fast64_t/uint_least64_t,如果你需要最大可用类型,则应该使用uintmax_t

然后你仍在做假设。如果想要具有可移植性,最好计算msb并设置它。 - this
@this是的,sizeof(type) * CHAR_BIT不是最佳解决方案,但至少它从OP的方法中删除了硬编码的8 - Arkku

0
由于负整数的二进制补码表示法,最小的负整数恰好是所需的位模式,只有最高位设置。因此,x |=(unsigned long long)LONG_LONG_MIN; 也应该有效。

1
C语言并不保证使用2的补码,因此任何依赖于它的实现最多只能依赖于具体实现。 - too honest for this site

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接