从x?y:z表达式中得到意外的答案 这里是一个简单的C++片段: int x1 = 10, x2 = 20, y1 = 132, y2 = 12, minx, miny, maxx, maxy; x1 <= x2 ? minx = x1, maxx = x2 : minx = x2, maxx = x1; y1 <= y2 ? miny = y1, maxy = y2 : miny = y2, maxy = y1; cout << "minx=" << minx << "\n"; cout << "maxx=" << maxx << "\n"; cout << "miny=" << miny << "\n"; cout <<" maxy=" << maxy << "\n";

从x?y:z表达式中得到意外的答案 这里是一个简单的C++片段: int x1 = 10, x2 = 20, y1 = 132, y2 = 12, minx, miny, maxx, maxy; x1 <= x2 ? minx = x1, maxx = x2 : minx = x2, maxx = x1; y1 <= y2 ? miny = y1, maxy = y2 : miny = y2, maxy = y1; cout << "minx=" << minx << "\n"; cout << "maxx=" << maxx << "\n"; cout << "miny=" << miny << "\n"; cout <<" maxy=" << maxy << "\n";,c++,c,operator-precedence,conditional-operator,comma-operator,C++,C,Operator Precedence,Conditional Operator,Comma Operator,但实际上结果是: minx=10 maxx=10 miny=12 maxy=132 有人能解释一下为什么maxx不是20?谢谢。由于运算符优先级,表达式的解析方式如下: (x1<=x2 ? minx=x1,maxx=x2 : minx=x2), maxx=x1; _Z4mineiiii: .LFB966: .cfi_startproc movq %rbx, -32(%rsp) movq %rbp, -24(%rsp) movl %ecx

但实际上结果是:

minx=10
maxx=10
miny=12
maxy=132

有人能解释一下为什么
maxx
不是
20
?谢谢。

由于运算符优先级,表达式的解析方式如下:

(x1<=x2 ? minx=x1,maxx=x2 : minx=x2), maxx=x1;
_Z4mineiiii:
.LFB966:
    .cfi_startproc
    movq    %rbx, -32(%rsp)
    movq    %rbp, -24(%rsp)
    movl    %ecx, %ebx
    movq    %r12, -16(%rsp)
    movq    %r13, -8(%rsp)
    movl    %esi, %r12d
    subq    $40, %rsp
    movl    %edi, %r13d
    cmpl    %esi, %edi
    movl    %edx, %ebp
    cmovg   %edi, %r12d
    cmovg   %esi, %r13d
    movl    $_ZSt4cout, %edi
    cmpl    %ecx, %edx
    movl    $.LC0, %esi
    cmovg   %edx, %ebx
    cmovg   %ecx, %ebp
        .... removed actual printout code that is quite long and unwieldy... 
_Z8originaliiii:
    movq    %rbx, -32(%rsp)
    movq    %rbp, -24(%rsp)
    movl    %ecx, %ebx
    movq    %r12, -16(%rsp)
    movq    %r13, -8(%rsp)
    movl    %esi, %r12d
    subq    $40, %rsp
    movl    %edi, %r13d
    cmpl    %esi, %edi
    movl    %edx, %ebp
    cmovg   %edi, %r12d
    cmovg   %esi, %r13d
movl    $_ZSt4cout, %edi
cmpl    %ecx, %edx
movl    $.LC0, %esi
cmovg   %edx, %ebx
cmovg   %ecx, %ebp
        ... print code goes here ... 
_Z6romanoiiii:
    movq    %rbx, -32(%rsp)
    movq    %rbp, -24(%rsp)
    movl    %edx, %ebx
    movq    %r12, -16(%rsp)
    movq    %r13, -8(%rsp)
    movl    %edi, %r12d
    subq    $40, %rsp
    movl    %esi, %r13d
    cmpl    %esi, %edi
    movl    %ecx, %ebp
    cmovle  %edi, %r13d
    cmovle  %esi, %r12d
movl    $_ZSt4cout, %edi
cmpl    %ecx, %edx
movl    $.LC0, %esi
cmovle  %edx, %ebp
cmovle  %ecx, %ebx
        ... printout code here.... 

(x1条件运算符的优先级大于逗号运算符的优先级,因此

x1<=x2 ? minx=x1,maxx=x2 : minx=x2,maxx=x1;
  • 如果出现以下情况,请使用

    if (x1 <= x2) {
        minx = x1;
        maxx = x2;
    } else {
        minx = x2;
        maxx = x1;
    }
    

    if(x1由于运算符优先级:


    (x1关于操作优先级和代码生成的有趣问题

    好的,
    操作的优先级非常低(最低,请参阅)。由于这一事实,您的代码与以下行相同:

    ((x1<=x2) ? minx=x1,maxx=x2 : minx=x2),maxx=x1;
    ((y1<=y2) ? miny=y1,maxy=y2 : miny=y2),maxy=y1;
    
    展望未来,我建议以这种方式重写您的片段,在效率和可读性之间保持平衡:

    minx = ((x1 <= x2) ? x1 : x2);
    maxx = ((x1 <= x2) ? x2 : x1);
    miny = ((y1 <= y2) ? y1 : y2);
    maxy = ((y1 <= y2) ? y2 : y1);
    

    minx=((x1虽然其他人已经解释了问题的原因,但我认为“更好”的解决方案应该是使用if编写条件:

    int x1 = 10, x2=20, y1=132, y2=12, minx, miny, maxx, maxy;
    if (x1<=x2) 
    { 
       minx=x1;
       maxx=x2;
    }
    else
    {
       minx=x2; 
       maxx=x1;
    }
    if (y1<=y2)
    {
        miny=y1;
        maxy=y2;
    } 
    else 
    {
        miny=y2;
        maxy=y1;
    }
    
    这是源代码(我必须设置它的参数,以确保编译器不只是直接计算正确的值,而且只做
    mov$12,%rdx
    ,而是实际做了一个比较,并决定使用更大的值):


    正如你所看到的,
    mine
    original
    是相同的,
    romano
    使用稍有不同的寄存器和不同形式的
    cmov
    ,但是它们在相同数量的指令中做同样的事情。

    在C++11中,你可以使用
    std::tie
    std::make\u-pair
    来制作这个obv一目了然(TM)


    联机。

    括号解决了问题……这是另一个使用条件表达式“不要太聪明”的理由,可以使用
    if
    来代替。编译器将以任何方式执行相同的操作[假设您添加了相关的括号,以便它能够执行您实际需要的操作].三元表达式有时可能有用,但这是一个很好的例子,说明了不应该使用它们。(不管怎样,为什么不:
    maxx=x1>x2?x1:x2
    ?为什么不包括
    maxi=std::max(x1,x2)
    ?当我第一次看到这个问题的标题时,我认为它是。+1.问题中发布的代码正是那种让许多组织干脆干脆禁止三元运算符的代码。三元运算符有它的位置,但发布的用法不是那个位置。是的,它长了几行——如果你你使用了1TB.:@DavidHammen是的,你可以用其他方式来设计它(这正是我通常编写自己代码的方式),但可能不会(在不让代码变得非常混乱的情况下)将它减少到两行……甚至四行可读性相当好的行也在推动它。因此该语句仍然“长了几行”。我的意思是让它更可读,而不是适合IOCCC条目的东西。+1.条件运算符在这里看起来不太好。我发布了另一个变体,它使用“短”条件运算符,可以使代码尽可能可读/紧凑。有趣的是机器代码将如何生成。条件的一个优点是al运算符使编译器更有可能使用
    cmov
    操作,从代码中删除潜在的管道气泡。+1用于测试生成代码中的差异并提供可读性参数。
    if (x1 <= x2) {
        minx = x1;
        maxx = x2;
    } else {
        minx = x2;
        maxx = x1;
    }
    
    int x1=10, x2=20, y1=132, y2=12, minx, miny, maxx, maxy;
    x1<=x2 ? (minx=x1,maxx=x2) : (minx=x2,maxx=x1);
    y1<=y2 ? (miny=y1,maxy=y2) : (miny=y2,maxy=y1);
    cout<<"minx="<<minx<<"\n";
    cout<<"maxx="<<maxx<<"\n";
    cout<<"miny="<<miny<<"\n";
    cout<<"maxy="<<maxy<<"\n";
    
    ((x1<=x2) ? minx=x1,maxx=x2 : minx=x2),maxx=x1;
    ((y1<=y2) ? miny=y1,maxy=y2 : miny=y2),maxy=y1;
    
    int a = 2;
    int b = (a == 2|1); // Looks like check for expression result? Nope, results 1!
    
    minx = ((x1 <= x2) ? x1 : x2);
    maxx = ((x1 <= x2) ? x2 : x1);
    miny = ((y1 <= y2) ? y1 : y2);
    maxy = ((y1 <= y2) ? y2 : y1);
    
    int x1 = 10, x2=20, y1=132, y2=12, minx, miny, maxx, maxy;
    if (x1<=x2) 
    { 
       minx=x1;
       maxx=x2;
    }
    else
    {
       minx=x2; 
       maxx=x1;
    }
    if (y1<=y2)
    {
        miny=y1;
        maxy=y2;
    } 
    else 
    {
        miny=y2;
        maxy=y1;
    }
    
    g++ -O2 -fno-inline -S -Wall ifs.cpp
    
    void mine(int x1, int x2, int y1, int y2)
    {
        int minx, miny, maxx, maxy;
        if (x1<=x2) 
        { 
        minx=x1;
        maxx=x2;
        }
        else
        {
        minx=x2; 
        maxx=x1;
        }
        if (y1<=y2)
        {
        miny=y1;
        maxy=y2;
        } 
        else 
        {
        miny=y2;
        maxy=y1;
        }
    
        cout<<"minx="<<minx<<"\n";
        cout<<"maxx="<<maxx<<"\n";
        cout<<"miny="<<miny<<"\n";
        cout<<"maxy="<<maxy<<"\n";
    }
    
    void original(int x1, int x2, int y1, int y2)
    {
        int minx, miny, maxx, maxy;
        x1<=x2 ? (minx=x1,maxx=x2) : (minx=x2,maxx=x1);
        y1<=y2 ? (miny=y1,maxy=y2) : (miny=y2,maxy=y1);
        cout<<"minx="<<minx<<"\n";
        cout<<"maxx="<<maxx<<"\n";
        cout<<"miny="<<miny<<"\n";
        cout<<"maxy="<<maxy<<"\n";
    }
    
    void romano(int x1, int x2, int y1, int y2)
    {
        int  minx, miny, maxx, maxy;
    
        minx = ((x1 <= x2) ? x1 : x2);
        maxx = ((x1 <= x2) ? x2 : x1);
        miny = ((y1 <= y2) ? y1 : y2);
        maxy = ((y1 <= y2) ? y2 : y1);
        cout<<"minx="<<minx<<"\n";
        cout<<"maxx="<<maxx<<"\n";
        cout<<"miny="<<miny<<"\n";
        cout<<"maxy="<<maxy<<"\n";
    }
    
    int main()
    {
        int x1=10, x2=20, y1=132, y2=12;
        mine(x1, x2, y1, y2);
        original(x1, x2, y1, y2);
        romano(x1, x2, y1, y2);
        return 0;
    }
    
    _Z4mineiiii:
    .LFB966:
        .cfi_startproc
        movq    %rbx, -32(%rsp)
        movq    %rbp, -24(%rsp)
        movl    %ecx, %ebx
        movq    %r12, -16(%rsp)
        movq    %r13, -8(%rsp)
        movl    %esi, %r12d
        subq    $40, %rsp
        movl    %edi, %r13d
        cmpl    %esi, %edi
        movl    %edx, %ebp
        cmovg   %edi, %r12d
        cmovg   %esi, %r13d
        movl    $_ZSt4cout, %edi
        cmpl    %ecx, %edx
        movl    $.LC0, %esi
        cmovg   %edx, %ebx
        cmovg   %ecx, %ebp
            .... removed actual printout code that is quite long and unwieldy... 
    _Z8originaliiii:
        movq    %rbx, -32(%rsp)
        movq    %rbp, -24(%rsp)
        movl    %ecx, %ebx
        movq    %r12, -16(%rsp)
        movq    %r13, -8(%rsp)
        movl    %esi, %r12d
        subq    $40, %rsp
        movl    %edi, %r13d
        cmpl    %esi, %edi
        movl    %edx, %ebp
        cmovg   %edi, %r12d
        cmovg   %esi, %r13d
    movl    $_ZSt4cout, %edi
    cmpl    %ecx, %edx
    movl    $.LC0, %esi
    cmovg   %edx, %ebx
    cmovg   %ecx, %ebp
            ... print code goes here ... 
    _Z6romanoiiii:
        movq    %rbx, -32(%rsp)
        movq    %rbp, -24(%rsp)
        movl    %edx, %ebx
        movq    %r12, -16(%rsp)
        movq    %r13, -8(%rsp)
        movl    %edi, %r12d
        subq    $40, %rsp
        movl    %esi, %r13d
        cmpl    %esi, %edi
        movl    %ecx, %ebp
        cmovle  %edi, %r13d
        cmovle  %esi, %r12d
    movl    $_ZSt4cout, %edi
    cmpl    %ecx, %edx
    movl    $.LC0, %esi
    cmovle  %edx, %ebp
    cmovle  %ecx, %ebx
            ... printout code here.... 
    
    #include <tuple>
    #include <utility>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        int x1 = 10, x2=20, y1=132, y2=12, minx, miny, maxx, maxy;
    
        tie(minx, maxx) = (x1 <= x2)? make_pair(x1, x2) : make_pair(x2, x1);
        tie(miny, maxy) = (y1 <= y2)? make_pair(y1, y2) : make_pair(y2, y1);
    
        cout<<"minx="<<minx<<"\n";
        cout<<"maxx="<<maxx<<"\n";
        cout<<"miny="<<miny<<"\n";
        cout<<"maxy="<<maxy<<"\n";
    }
    
    #include <algorithm>
    #include <tuple>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        int x[] = { 10, 20 }, y[] = { 132, 12 }, *minx, *miny, *maxx, *maxy;
    
        tie(minx, maxx) = minmax_element(begin(x), end(x));
        tie(miny, maxy) = minmax_element(begin(y), end(y));
    
        cout<<"minx="<<*minx<<"\n";
        cout<<"maxx="<<*maxx<<"\n";
        cout<<"miny="<<*miny<<"\n";
        cout<<"maxy="<<*maxy<<"\n";
    }