C++ Is(int32_t)255<&书信电报;24 gcc中未定义的行为(C+;+;11)?

C++ Is(int32_t)255<&书信电报;24 gcc中未定义的行为(C+;+;11)?,c++,c++11,language-lawyer,undefined-behavior,bit-shift,C++,C++11,Language Lawyer,Undefined Behavior,Bit Shift,在C++11中,根据 对于有符号和非负a,a的值“未定义的行为是标准没有规定的。”这意味着它甚至可以是预期/正确的行为。关于移位算子的C++标准状态。< /P> 8.5.7班次操作员[expr.Shift](C++标准草案N4713) 操作数应为整数或无范围枚举类型,并执行整数升级。结果的类型是提升的左操作数的类型。如果右操作数为负,或大于或等于提升后的左操作数的位长度,则该行为不确定。否则,如果E1具有有符号类型和非负值,并且E1×2E2可在结果类型的相应无符号类型中表示,则转换为结果类型的该

在C++11中,根据

对于有符号和非负a,a的值“未定义的行为是标准没有规定的。”这意味着它甚至可以是预期/正确的行为。关于移位算子的C++标准状态。< /P> 8.5.7班次操作员[expr.Shift](C++标准草案N4713)

  • 操作数应为整数或无范围枚举类型,并执行整数升级。结果的类型是提升的左操作数的类型。如果右操作数为负,或大于或等于提升后的左操作数的位长度,则该行为不确定。否则,如果
    E1
    具有有符号类型和非负值,并且
    E1×2E2
    可在结果类型的相应无符号类型中表示,则转换为结果类型的该值即为结果值;否则,行为是不确定的
    <@ @ RuStux注释如下,“措辞”<代码> E1×2E2在对应类型的“无符号类型”中是可表示的,“不幸的是,仍然是UB。”

    < P> C++ 14之前的C++编译器,如果你有这样的函数:

    // check if the input is still positive,
    // after a suspicious shift
    
    bool test(int input)
    {
        if (input > 0) 
        {
            input = input << 24;
    
            // how can this become negative in C++11,
            // unless you are relying on UB?
    
            return (input > 0); 
        }
        else 
        {
            return false;
        }
    }
    
    //检查输入是否仍然为正,
    //在一次可疑的转变之后
    布尔测试(整数输入)
    {
    如果(输入>0)
    {
    输入=输入0);
    }
    其他的
    {
    返回false;
    }
    }
    
    然后,允许优化编译器将其更改为:

    bool test(int input)
    {
        // unless you are relying on UB, 
        // input << 24 must fit into an int,
        // and input is positive in that branch
    
        return (input > 0);
    }
    
    bool测试(int输入)
    {
    //除非你依赖UB,
    //输入0);
    }
    
    每个人都很高兴,因为你在发布版本中得到了很好的加速


    然而,我不知道有哪种编译器会对左班进行这样的优化,尽管对添加进行优化是很常见的,因为。

    这是随着时间的推移而改变的,而且有很好的理由,所以让我们回顾一下历史。请注意,在所有情况下,只要执行
    static_cast(255u,GNUC编译器就会完全按照以下说明定义左/右移位:

    GCC只支持两个补码整数类型,所有位模式都是普通值


    作为C语言的一个扩展,GCC不使用C99和C11中给出的纬度,只处理带符号的“
    ”的某些方面。未定义的行为是标准没有要求的这意味着它甚至可以是预期的/正确的行为。编译器可能会在某些约束条件下执行此操作。根据您的链接,GCC希望仅对负值进行未定义。GNU C参考说明:“对于这两个>,如果第二个操作数大于第一个操作数的位宽度,或者第二个操作数为负,则行为未定义”。在某种程度上,这意味着您的问题的答案是“是”“但是,这可能不是详尽无遗的;它没有明确说明,我认为假设“是”是危险的。”也就是GNU C参考文档C而不是C++。@ PSkocik,很明显,OP询问GCC,一个实现,即使它被语言标准定义了,也定义了一个行为。@ HSPSPANTAN: RE“它将具有可预测和可重复的值”。当前位置:我仍在寻找一个令人信服的论据,证明在当前和所有未来的Arduino环境中这是正确的。我愿意想当然地认为Arduino将坚持gcc,但不会坚持gcc的特定版本。但这并不能回答问题。如果这些是转变可能具有未定义行为的唯一方式,那么OP的问题的答案是“不”;但从这段引文中不清楚情况是否如此。(值得注意的是,您遗漏了:否则,如果E1具有有符号类型和非负值,并且E1×2 E2可在结果类型的相应无符号类型中表示,那么转换为结果类型的值就是结果值;否则,行为未定义)@davmac:现在添加了。OP似乎已经知道该部分,所以最初没有添加。措辞“E1×2E2可在结果类型的相应无符号类型中表示”不幸的是,.UB仍然存在。@davmac:不幸的是,该标准没有提供任何方法,通过这些方法,实现可以承诺支持无声环绕行为产生的一些最有用的保证,例如保证整数运算符(复合赋值运算符除外)除了可能触发实现定义的陷阱外,不会产生任何副作用。在许多情况下,保证一个操作将产生特定的结果可能是昂贵的,但保证它将在没有副作用的情况下继续进行基本上不需要任何成本。感谢您的回答,但我已经意识到了这一点。我已经如果(x>=0&&&(xOh,好吧,那么,我的印象是,您可以使用不同的编译器为arduino编译(毕竟有人使用),那么ied将gcc优化出
    失败,但如果这是特定于g++的,那么标准基本上是不相关的。我想您可以使用不同的编译器,但由于Arduino环境使用gcc,它是某种“Arduino标准编译器”。而且C++11标准仍然相关,因为gcc应该是“兼容的实现”.FWIW,你在链接线程中的参数是有效的,在C++11下是UB。它不可移植,将来的gcc版本可能(理论上)用
    -std=c++11
    打破它。我说理论上是因为程序员习惯于无视标准,这样的改变可能会破坏大量现有代码。解决方案只是对
    uint32\u t
    进行转换,然后再进行转换,所以我不明白为什么这家伙反对让它可移植。我会将其与强制t进行比较他