C++ 为什么要担心';未定义的行为';在>&燃气轮机;签名类型?

C++ 为什么要担心';未定义的行为';在>&燃气轮机;签名类型?,c++,c,hardware,bit-manipulation,undefined-behavior,C++,C,Hardware,Bit Manipulation,Undefined Behavior,我的问题涉及并将包含几个问题 对我来说,上述问题最明显的解决方案(意味着我会在代码中使用它)是: uint8_t x = some value; x = (int8_t)x >> 7; 是的,是的,我听到你们所有人。。。。未定义的行为,这就是为什么我没有发布我的“解决方案” 我有一种感觉(也许这只是我的病态想法)“未定义的行为”一词被过度使用了,只是为了证明如果问题被标记为c/c++,就可以否决某人 所以,让我们(暂时)把C/C++标准放在一边,想想日常生活/编程、真正的编译器实现

我的问题涉及并将包含几个问题

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

uint8_t x = some value;
x = (int8_t)x >> 7;
是的,是的,我听到你们所有人。。。。未定义的行为,这就是为什么我没有发布我的“解决方案”

我有一种感觉(也许这只是我的病态想法)“未定义的行为”一词被过度使用了,只是为了证明如果问题被标记为c/c++,就可以否决某人

所以,让我们(暂时)把C/C++标准放在一边,想想日常生活/编程、真正的编译器实现以及它们为当代硬件生成的代码

考虑到以下因素:

  • 据我记忆所及,我遇到的所有硬件都有不同的算术和逻辑移位指令
  • 我所知道的所有编译器都将
    >
    转换为有符号类型的算术移位和无符号类型的逻辑移位
  • 我想不起在c/c++代码中使用
    >
    时,有哪一个编译器发出过类似于
    div
    的低级指令(这里我们不讨论运算符重载)
  • 我知道的所有硬件都使用U2
所以。。。是否有任何东西(当代编译器、硬件)的行为与上面提到的不同?简单地说,我是否应该担心右移符号值没有被转换为算术移位

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

请讲实话;-)

为什么要担心有符号类型的>>中的“未定义行为”

因为现在任何特定的未定义行为定义得多么好都无关紧要;关键是它可能在未来的任何时候崩溃。你所依赖的副作用可能在任何时候出于任何原因或没有任何原因而被优化(或未优化)


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

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

特别是编译器中的优化阶段。这些方法利用了变量的已知可能值,并将从UB的缺失中导出这些可能值。如果指针被解引用,则指针必须为非空;如果用作除法器,则整数必须为非零;右移值必须为非负

这可以追溯到过去:

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

归根结底,你愿意冒险吗

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


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

根据C11(§6.5.7 p 5)在右移中使用有符号类型不是未定义的行为,而是实现定义的行为。我不会像在未定义的行为中那样得到未定义中没有得到的东西。你的电脑可能会着火,你可能会得到鼻恶魔。如果你的编译器能保证某些东西,你可以依靠它,但只能依靠那个特定的编译器。@Artur我不认为是的。我和Kninnug的观点是,当你右移一个负整数时,没有未定义的行为,所以如果你明白这一点,为什么你要提到未定义的行为?:)以基于意见的方式结束这个问题是不明智的。有合理的理由不编写显示UB的代码,因此结束这个问题只会验证OP的观点,即“未定义的行为”被过度使用,只是为了证明如果问题被标记为c/c++,就有理由否决某人。”这无助于他或其他人编写更好的代码。这是一个调查问题,而这些通常被认为是离题的。我发现不太可能有任何一个人能够为所有平台上所有编译器的行为负责。实际上,答案将局限于回答者认为重要的一些实现子集。为了补充@meagar所说的关于未来的内容,您使用4而不是sizeof(int),因为这更简单,然后是64位计算机和位a*s@fernando.reyes:那不一样。我想你没有领会我的意思。我不认为我会醒来,编译器会将
>
翻译成与shift不同的东西。@Artur正如您所说的“我知道的所有编译器都会翻译…”,您将未定义的行为作为您知道的编译器当前状态的重要假设,但是,也许将来的编译器或者你不认识的编译器会以不同的方式对待它,并且它会是undefined@Artur:实际上,任何合适的编译器都会将
2>>1
转换为常量1,因此没有汇编程序级别的转换。当然,一些未定义或实现定义的行为是很麻烦的,因此,在实践中,这是开发时间和可移植性之间的权衡。不必担心16位整数是一种方便,在某些项目上可能值得,而且我认为我们都同意在C89代码的外部名称中假设超过6个不区分大小写的唯一字符。有符号右移和有符号整数除法(在C89中,不是C99或C11)是实现定义的,而不是未定义的行为。在当前绝大多数指定算术右移的编译器上,这很好。@doynax: