【问题标题】:What is wrong with this bit-manipulation code from an interview question?面试问题中的这个位操作代码有什么问题?
【发布时间】:2011-05-14 05:02:12
【问题描述】:

我正在查看此页面:http://www.devbistro.com/tech-interview-questions/Cplusplus.jsp,但不明白这个问题:

以下代码可能有什么问题?

long value;
//some stuff
value &= 0xFFFF;

注意:向候选人提示他们正在开发的基础平台。如果该人仍然没有发现代码有任何问题,则说明他们没有 C++ 经验。

谁能详细说明一下?

谢谢!

【问题讨论】:

  • 这段代码可能有很多问题。另一方面,它可能很好。没有上下文,就不可能为这个问题提供一个合理的答案。
  • @James:也许在某些实现上,也许不是。无论如何,这都是一个糟糕的借口。
  • 我删除了关于符号扩展的答案,因为它是错误的。我怀疑这是面试官正在寻找的,但如果面试官正在寻找,他们也错了。
  • 一个人可以“有 C++ 经验”并且从不使用位运算符。 C++ 是如此庞大的语言,它支持如此多的编程范例(除了“Hello World!”类型的东西)我不确定是否有可能根据 1 个问题明确确定一个人是否有经验。
  • Axn: 0xffff 在任何情况下都不会被提升为0xffffffff - 0xffff 始终与65535 相同,这意味着该常量具有如果 int 只有 16 位,则键入 unsigned int。当提升为 long 时,它将保持为 0xffff / 65535

标签: c++ c bit-manipulation integer-promotion


【解决方案1】:

这里有几个答案指出,如果 int 的宽度为 16 位,则 0xFFFF 是否定的。这不是真的。 0xFFFF 绝不是负面的。

十六进制文字由以下第一个足以包含它的类型表示:intunsigned intlongunsigned long

如果int 的宽度为16 位,则0xFFFF 大于int 可表示的最大值。因此,0xFFFF 的类型为unsigned int,保证足够大以表示@​​987654333@。

当为评估& 执行通常的算术转换时,unsigned int 将转换为long。 16 位 unsigned intlong 的转换是明确定义的,因为可以由 16 位 unsigned int 表示的每个值也可以由 32 位 long 表示。

由于初始类型没有签名,所以不需要符号扩展,使用0xFFFF的结果与使用0xFFFFL的结果相同。

或者,如果 int 的宽度超过 16 位,则 0xFFFF 的类型为 int。这是一个有符号但为正的数字。在这种情况下,两个操作数都有符号,并且long 具有更高的转换等级,因此int 通过通常的算术转换再次提升为long


正如其他人所说,您应该避免对有符号操作数执行按位运算,因为数字结果取决于符号的表示方式。

除此之外,这段代码并没有什么特别的问题。我会争辩说,value 在声明时未初始化是一种风格问题,但这可能是一个挑剔的评论,取决于被省略的//some stuff 部分的内容。

为了更好的可移植性,使用固定宽度整数类型(如uint32_t)而不是long 可能更可取,但这也取决于您编写的代码以及您的基本假设。

【讨论】:

  • 你是对的。我敢打赌,问这个问题的面试官会被证明是错误的。 :-)
  • @Omnifarious:很有可能。不管怎样,我认为这是一个糟糕的面试问题。
  • 请注意,仅当涉及负数/符号位时,对有符号操作数进行按位运算的数值结果才会有所不同。例如,在这种情况下,如果value 为正,则结果是明确定义的(与value % 65536 相同),但如果value 为负,则有三种可能的结果。
  • 出于兴趣,caf 提到的三个可能结果是什么?
【解决方案2】:

我认为根据 long 的大小,可以将 0xffff 文字 (-1) 提升为更大的大小,并且作为有符号值,它将被符号扩展,可能变成 0xffffffff(仍然是 -1)。

【讨论】:

  • 0xFFFF 永远不会是负数。我已经发布了详细的答案。
【解决方案3】:

我假设这是因为 long 没有预定义的大小,除了它必须至少与前面的大小 (int) 一样大。因此,根据大小,您可能会将值截断为位子集(如果 long 超过 32 位)或溢出(如果它小于 32 位)。

是的,多头(根据规范,感谢 cmets 中的提醒)必须至少能够持有 -2147483647 到 2147483647(LONG_MIN 和 LONG_MAX)。

【讨论】:

  • 你的意思是它是否小于/大于 16 位?
  • +1 - 在看这个问题时,我没有想到 long 的大小会发生变化。
  • 我以为只是 int 的大小未定义,long = 32bit,long long = 64bit。但是ferenuff,一个人每天都会学到一些东西:)
  • -1 long 保证至少 32 位,参考 C 标准(它遵循保证值范围)。因此,该声明在技术上没有任何问题。它掩盖了除值的低 16 位之外的所有内容,仅此而已,如果这是意图(并且已分配值),则代码是正确的,如果不是意图,则代码是错误的。面试官不懂C++。干杯&hth.,
  • @GMan int 是这样,long 必须至少为 32 位。
【解决方案4】:

对于一个值在执行之前没有初始化,所以我认为行为是未定义的,值可以是任何东西。

【讨论】:

  • 它不是未定义的——内容可能是垃圾,但它不能(例如)格式化你的硬盘。
  • @Billy:形式上它可以做鼻部守护进程。但实际上,在 32 位系统上,int 类型的不确定值只是 some int 值。在 64 位系统上,+ 在一些非常古老的架构上,可能会有检查和陷阱。干杯,
  • @Alf:是的,变量的实际内容是未定义的。这并不意味着它是未定义的行为。如果这是未定义的行为,则符合标准的编译器可以格式化您的硬盘驱动器。而在这种情况下,它只允许将垃圾放入单个变量中。
  • @Billy:读取(执行左值到右值的转换)未初始化的变量确实是未定义的行为。它可以很好地重新格式化您的硬盘。见§4.1。
【解决方案5】:

long 类型大小取决于平台/编译器。

你可以在这里说的是:

  1. 已签名。
  2. 我们无法知道 value &= 0xFFFF 的结果;因为它可能是例如 value &= 0x0000FFFF;并且不会做预期的事情。

【讨论】:

  • 同样,long 并不意味着 4 个字节。它只意味着 >= sizeof(int)
  • @Billy 和@Charles:Julio 没有说四个字节。他暗示long 的大小可以是 32 位(取决于CHAR_BIT,可能是1、2 或4 个字节)。 long 的最小 32 位大小由标准保证,因此它确实可以是 32 位。干杯&hth。
【解决方案6】:

虽然有人可能会争辩说,由于它不是缓冲区溢出或其他一些可能被利用的错误,它是一种风格的东西而不是一个错误,但我 99% 有信心得到答案问题作者正在寻找的是 value 在分配之前对其进行操作。该值将是任意垃圾,这不太可能是本意,因此“可能是错误的”。

【讨论】:

    【解决方案7】:

    使用 MSVC,我认为该语句将执行最可能的预期 - 即:清除除最不重要的 16 位值之外的所有值,但我遇到其他平台会将文字 0xffff 解释为等同于(短) -1,然后符号 extend 转换为 long,在这种情况下语句“value &= 0xFFFF”将无效。 "value &= 0x0FFFF" 更加明确和健壮。

    【讨论】:

      猜你喜欢
      • 2012-08-07
      • 2014-08-29
      • 2013-06-05
      • 2014-06-04
      • 2011-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多