【问题标题】:set most significant bit in C在 C 中设置最高有效位
【发布时间】:2015-09-22 20:50:13
【问题描述】:

我正在尝试在 long long unsigned x 中设置最高有效位。 为此,我正在使用这行代码:

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

我认为这应该可行,因为 sizeof 以字节为单位给出大小,所以我乘以 8 并减去 1 来设置最后一位。每当我这样做时,编译器都会发出以下警告:“警告:左移计数> =类型宽度”

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

【问题讨论】:

  • 不要使用幻数。 C 中的 byte/char 可以有超过 8 位。将8 替换为CHAR_BIT

标签: c bit-manipulation


【解决方案1】:

您要移位的1int 类型的常量,这意味着您将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)

【讨论】:

  • 我喜欢这些新方法,尽管它们并不明显。
  • 对一个不错的答案投了赞成票,您还能说明~(-1ull &gt;&gt; 1)~(~0ull &gt;&gt; 1) 如何成为更好的方法吗?
  • @rakeb.void 因为它更紧凑,不依赖于CHAR_BIT 或其他常量,并且更易于阅读(并且更小)。
  • @rakeb.void:它“更好”,因为它的冗余更少。原始变体以两种方式取决于目标类型:文字后缀ull 和移位距离sizeof(x) * CHAR_BIT。这种替代方法只有一个依赖项 - 文字后缀。虽然乍一看不太明显,但程序员应该知道它是一个惯用语。
  • 为避免依赖文字后缀,请使用正确整数类型的表达式:~((x|~x)&gt;&gt;1)~(~(x^x)&gt;&gt;1),任何自尊的编译器都应将这两者进行常量折叠。 (这仅在 x 至少与 int 一样宽时才有效,但我认为在这种情况下这不是问题。)
【解决方案2】:

使用 1ULL

仅使用“1”可以移动一个整数。 1ULL 将是一个 unsigned long long 这是你所需要的。 一个整数可能是 32 位,long long 可能是 64 位宽。所以转变:

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

将是(很可能):

1 << 63

由于 1 是(很可能)32 位的整数,因此您会收到警告,因为您试图移过 32 位值的 MSB。

【讨论】:

  • 整数不是“最有可能”的 32 位。有许多具有 16 位整数的体系结构,一些具有 24 位整数的体系结构,等等(但是,您对 UB 是正确的)。
  • @Olaf:是的,我知道 - int 的大小不仅取决于架构,还取决于编译器。一个人可以有 2 个编译器用于相同的 cpu 和不同的 int 大小。这里有很多细微差别。
【解决方案3】:

您要移位的文字 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_tuintmax_t如果您需要最大的可用类型。

【讨论】:

  • 然后你还在做假设。如果你想便携,最好计算 msb 并设置它。
  • @this 是的,sizeof(type) * CHAR_BIT 不是最好的解决方案,但至少它从 OP 的方法中删除了硬编码的8
【解决方案4】:

由于负整数的 2 的补码表示,最负整数正是所需的位模式,只有 MSB 集。所以x |= (unsigned long long )LONG_LONG_MIN; 也应该可以工作。

【讨论】:

  • C 实际上并不保证 2s 补码,因此任何依赖于它的实现充其量只能依赖于实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-13
  • 2011-08-26
  • 2017-11-18
  • 2011-05-05
  • 2020-09-07
  • 1970-01-01
  • 2016-07-11
相关资源
最近更新 更多