【问题标题】:Assigning bits to a 64-bit variable将位分配给 64 位变量
【发布时间】:2014-06-12 19:27:11
【问题描述】:

我对位操作有点陌生。我正在尝试将信息存储在 int64_t 变量中,如下所示:

int64_t u = 0;

for(i=0;i<44;i++)
   u |= 1 << i;

for(;i<64;i++)
   u |= 0 << i;

int t = __builtin_popcountl(u);

我的意图是将 44 个 1 存储在变量 u 中,并确保剩余位置均为 0,因此“t”返回 44。但是,它始终返回 64。对于其他变量,例如int32,它也失败了。为什么?

【问题讨论】:

  • 虽然第二个循环不会造成任何麻烦(那是因为它根本没有用处),u |= 0 &lt;&lt; i; 不是清除(设置为零)@987654323 的正确方法@th 位。您应该执行类似u &amp;= ~(1 &lt;&lt; i); 的操作来清除uith 位。 1 &lt;&lt; i1 向左移动i,然后~ 将反转整个事情。 anding 将清除 0 所在的位,这将是 ith 位,1 在反转之前。
  • 在第二个循环中,任何 | 0 都只是原始值。即,无论i 的值如何,u |= 0 &lt;&lt; i 使u 完全不变。
  • 在这种情况下,第一个循环会自行解决问题,不是吗?
  • u = (1u &lt;&lt; 44) -1;(你不需要循环)
  • 不,IIRC 你不需要 sizecast 1u 或 1ul 或 1ull 常量。 (也许如果它们超过本机机器寄存器大小)。无论如何,u = (1ull &lt;&lt; 44) -1; 可以。 @KeithThomson 下面有正确答案。

标签: c bit-manipulation bit bit-shift bitwise-or


【解决方案1】:

表达式的类型通常由表达式本身决定,而不是由它出现的上下文决定。

您的变量 uint64_t 类型(顺便说一下,uint64_t 会更好,因为您正在执行按位运算)。

在这一行:

u |= 1 << i;

因为1int 类型,1 &lt;&lt; i 也是int 类型。如果像典型的那样,int 是 32 位,那么对于较大的 i 值,这具有未定义的行为。

如果您将此行更改为:

u |= (uint64_t)1 << i;

它应该做你想做的。

您也可以将1 更改为1ULL。这给了它unsigned long long 的类型,保证至少为64 位,但不一定uint64_t 的类型相同。

【讨论】:

  • 你的建议给了我 t=6;
  • @a3mlord:啊!那是一个错字,现在更正了。对造成的混乱深表歉意。
  • 我认为标准所预见的产生正确常量的方式是UINT64_C(1)
  • 无需道歉,感谢您的帮助;顺便说一句,我想出了:uint64_t u = 0; uint64_t b = 1; for(i=0;i&lt;44;i++){ u = u|b; b = b&lt;&lt;1; } 在执行时间方面最有效的方法是什么?
【解决方案2】:
  1. __builtin_popcountl 将 unsigned long 作为其参数,它并不总是 64 位整数。我个人使用__builtin_popcountll,这需要很长时间。看来你不是这种情况
  2. 默认情况下,整数的类型为“int”,通过将 int 移动任何大于或等于 32 的值(准确地说,int 的大小以位为单位),您会得到未定义的行为。正确用法:u |= 1LL
  3. 与零进行或运算什么都不做。您不能只将位设置为特定值,您应该使用掩码 OR(如果要将某些位设置为 1)或与掩码的否定(如果要将某些位设置为 0)进行与,否定是通过蒂尔达 (~)。

【讨论】:

  • “整数默认类型为int”。这并不正确。整数 objects 具有它们被声明为具有的任何类型。整数 表达式 具有依赖于表达式的类型;没有默认值。这里的问题是常量1 的类型为int。无后缀十进制整数常量的类型是intlong intlong long int 中可以表示其值的第一个。 (在 C90 中,列表为 intlong intunsigned long int;在 C99 中发生了变化。)
【解决方案3】:

当您移入 32 位整数的高位并转换为 64 位时,符号位将延伸到高 32 位;然后您将设置所有 64 位,因为 默认情况下,您的文字 '1' 是有符号的 32 位 int。移位也不会影响高 32 位,因为该值只有 32 位;但是,当被转换的值为负时,将转换为 64 位。

这可以通过编写你的第一个循环来解决:

for(i=0;i<44;i++)
   u |= (int64_t)1 << i;

此外,这个循环什么也不做,因为与 0 的 ORing 不会改变值:

for(;i<64;i++)
   u |= 0 << i;

【讨论】:

    猜你喜欢
    • 2013-09-04
    • 2017-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-24
    • 1970-01-01
    • 2010-09-07
    相关资源
    最近更新 更多