【问题标题】:For loop with bitshifts带位移的 For 循环
【发布时间】:2020-06-02 09:29:18
【问题描述】:

谁能解释一下这个 foo 循环是如何工作的?

for (bitMask = 0x01; bitMask; bitMask <<= 1)

这是我第一次在 for 循环中遇到这样的语法,很想知道循环将如何结束。

【问题讨论】:

  • 最终,该单个位被移出整数的“顶部”,因此值变为零,循环结束。所以它实际上迭代了整数的每一位。
  • 这取决于所使用的变量的类型。在不知道的情况下猜测这段代码的作用是没有意义的。
  • 它要么等同于for (bitMask = 1; bitMask != 0; bitMask *= 2),要么具有未定义的行为。

标签: c++ c for-loop bit


【解决方案1】:

如果你有一个 unsigned int32 变量 bitMask。在第 32 个周期,它的位表示为

10000000 00000000 00000000 00000000

然后左移一位,溢出,只保留低32位,所以值变为0,循环条件为假。

1 00000000 00000000 00000000 00000000
↑
this bit is discarded

如果bitMask 是一个signed int 呢?那么这是一个未定义的行为。

C 标准(N2716,6.5.7 位移位运算符)说:

E1

C++ 标准(N4713,8.5.7 移位运算符)说:

E1的值

我的观点是永远不要使用这种循环,因为我们很容易忘记这只适用于无符号整数。相反,您应该使用以下内容为每个位生成掩码。

for (int i = 0; i < 32; i++) {
    int bitMask = 1 << i;
}

【讨论】:

  • 英特尔的手册在这里没有任何意义。 C++ 标准说有符号溢出是 UB。
【解决方案2】:

我认为 bitMask 的数据类型在这里很重要。所以将其视为int。下面会发生。

  1. bitMask 将被初始化为值 1。
  2. 每次迭代都会将 bitMask 的位值移动 1 位。
    例如。 1 = 00001(位数将取决于平台。考虑到 32 bit) 左移 1 将得到 00010 等于值 2
  3. 这将为 bitMask 生成以下值序列。 1,2,4,16,... 直到值为 1 的位溢出 32 位大小。
  4. 一旦溢出,int 的值将变为未定义。如果 bitMask 被认为是 Unsigned Int 则为 0,因为现在所有位都为零。使 for 循环中的条件为 false & break。

更简单易读的版本:

for (bitMask = 1; bitMask != 0; bitMask *= 2)

【讨论】:

  • 第 4 项应读作“4。一旦溢出,该值将变为未定义,没有人知道这些位会发生什么。”
  • bitMask 最好有一个无符号整数类型以避免未定义的行为。
  • 否:如果是int,程序一旦溢出就会有未定义的行为,所以不应该这样做。
猜你喜欢
  • 2013-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-17
  • 1970-01-01
  • 1970-01-01
  • 2021-10-27
相关资源
最近更新 更多