为什么要担心未定义的行为'在>>签名类型?

时间:2013-12-18 21:25:00

标签: c++ c hardware bit-manipulation undefined-behavior

我的问题与this one有关,并且几乎没有问题。

对我来说最明显的(意味着我会在我的代码中使用它)解决上述问题就是这样:

uint8_t x = some value;
x = (int8_t)x >> 7;

是的,是的,我听到你们所有人......未定义的行为,这就是为什么我没有发布我的“解决方案”。

我有一种感觉(也许只是我生病的头脑),术语“未定义的行为”在SO上被过度使用,只是为了证明如果问题被标记为c / c ++,那么就可以为某人辩护。

所以 - 让我们(暂时)抛开C / C ++标准,思考日常生活/编程,真正的编译器实现以及它们为现代硬件生成的代码。

考虑到以下因素:

  • 据我所知,我遇到的所有硬件都有不同的算术和逻辑移位指令。
  • 我知道的所有编译器都将>>转换为有符号类型的算术移位和无符号类型的逻辑移位。
  • 我记不起任何编译器发出div - 就像在c / c ++代码中使用>>时的低级指令一样(我们不是在讨论运算符重载)。
  • 我所知道的所有硬件都使用U2。

所以...有什么(任何当代编译器,硬件)的行为与上面提到的不同?简单地说,我是否应该担心右移有符号值而不是转换为算术移位?

我的'解决方案'在许多平台上只编译一个低级指令,而其他平台则需要多个低级指令。你会在代码中使用什么?

请真相; - )

3 个答案:

答案 0 :(得分:9)

  

为什么要担心>>中的'未定义的行为'?签名类型?

因为确定任何特定的未定义行为的定义并不重要现在;关键是它可能会在未来的任何时候破裂。您依赖于可能因任何原因或无理由而在任何时候被优化(或未优化)的副作用。

另外,在使用我不应该使用的东西之前,我不想要求有人详细了解许多不同编译器的实现,所以我跳过它。

答案 1 :(得分:2)

是的,有些编译器的行为与您的假设不同。

特别是编译器中的优化阶段。这些利用了已知的可变变量值,并将从缺少UB得出那些可能的值。如果指针被取消引用,则该指针必须为非空,如果整数必须为零,如果它被用作分频器,则右移位值必须为非负值。

这可以追溯到时间:

if (x<0) {
  printf("This is dead code\n");
}
x >> 3;

答案 2 :(得分:0)

真正归结为,你愿意承担风险吗?

“标准不保证yada yada”很好,但是现在说实话,风险并不大。如果你要在一个疯狂的平台上运行你的代码,你通常会提前知道。如果它让你感到意外,那就是你冒的风险。

此外,解决方法很糟糕。如果您不需要它,它只是用无意义的“函数调用而不是右移”来污染您的代码库,这将更难维护(从而带来成本)。并且你永远无法将其他地方的代码“粘贴并忘记”到项目中 - 你总是必须检查代码是否有可能正确地移动负的有符号整数。