【问题标题】:C-language binary shift operatorC语言二进制移位运算符
【发布时间】:2017-02-02 21:09:51
【问题描述】:

我正在尝试为一个项目学习一些基本的 C 语言。 在关于二元移位运算符的维基百科文章中:

如果变量 ch 包含位模式 11100101,则 ch >> 1 将产生结果 01110010,而 ch >> 2 将产生 00111001。

为了澄清,如果将二进制运算符的最后一位向右移动(>>1)会丢失吗?它不会像圆形阵列一样旋转到前面,对吗?

【问题讨论】:

  • C(古老的东西) - 你是想侮辱吗? :) 是的,移出的位丢失了。 C中没有圆形旋转
  • 是的,正确...
  • Visual Studio 不是最新 C 标准的好选择。
  • 所以你问维基百科在这方面是否正确?这样做并非完全不合理,但如果您认为它是正确的,那么它已经回答了您的问题(肯定的,它正确的)。
  • @Rizzo 最常见和标准定义的选择是GCC。我不明白你怎么能将 VS 与 C99 和 C11 一起使用,因为它不支持它们。

标签: c bit-manipulation


【解决方案1】:

以下是 C 的圣词(C 标准)关于向右位移的说法:

6.5.7p5:

E1 >> E2 的结果是 E1 右移 E2 位位置。如果 E1 有 一个无符号类型,或者如果 E1 有一个有符号类型和一个非负值, 结果的值是 E1 / 商的整数部分 2E2 。如果 E1 具有带符号类型和负值,则结果 value 是实现定义的。

换句话说: x>>n == x/two_to_the(n),虽然x<0 可能不是这样

(更直接的回答是,是的——除法时,最低有效位丢失)。

【讨论】:

  • 对。实际上,这很有趣,因为如果说的是你提到的东西,一个负数的有符号字符怎么办? (比如说-2)。我猜实现定义只是意味着基于您使用的 IDE 或框架
  • @KevinHu 实现定义和未定义的区别在于,您不应该调用或依赖未定义的行为,而您可以假设特定的实现定义的行为,给定您的代码不需要是可移植的,并且您的编译器实现正在执行您需要的操作。
  • @KevinHu 然后它是实现定义的,这就是为什么在那里使用实际除法可能是一个更好的主意(优化器往往足够聪明,可以注意到你正在除以一个常数,这是一个幂二,在这种情况下,他们会将操作转换为汇编级位移)。
  • @KevinHu,“实现定义”意味着 C 语言实现——实际上是编译器和相关的运行时支持——可以选择,而且它必须记录该选择。该行为对于该实现是可靠的。是的,如果您想确保跨实现的可移植性,那么您必须避免依赖实现定义的行为。
  • 哦,我明白了。定义的实现也是处理未签名和签名的东西,对吗?我相信如果您不指定标牌,那么实施将为您完成(内存密集度较低但更危险)
【解决方案2】:

是的。

如果x 为无符号或正数,移位操作x >> 1 将得到等于x 除以2 的值,如果x 为负数,则由实现定义(C.2011 §6.5.7 ¶5)。

【讨论】:

    【解决方案3】:

    对,最外面的位会丢失,除非你在移位前保存它的值:

    unsigned char ch = 229; 
    int lostBit = ch & 0x01;
    ch >>= 1;
    

    请注意,位移运算符>> 仅针对无符号或正值定义。在您的示例中,如果 ch 是有符号字符,则值 11100101 实际上表示负数 (-27),并且该操作将产生未定义的行为。

    【讨论】:

      猜你喜欢
      • 2022-11-03
      • 1970-01-01
      • 2013-11-18
      • 1970-01-01
      • 2014-06-25
      • 2017-08-04
      • 2021-08-17
      • 2014-01-02
      • 2012-09-25
      相关资源
      最近更新 更多