简体   繁体   中英

Is multiple variable comparision inline undefined behavior?

I was telling a friend of mine (which is learning C) that he couldn't do multiple variables comparision at once:

int main(){
    int a[4];

    scanf("%d %d %d %d", &a[0], &a[1], &a[2], &a[3]);

    if(a[0] < a[1] < a[2] < a[3]){
        printf("OK!\n");

    }

    else{
        printf("I've told ya\n");

    }

}

So, to prove I was right I've coded the program above and then I've executed it with 1 2 3 4 . Surprisingly it printed OK! . And so I didn't know what to tell him, because I was sure it wasn't right.

Finally, is it or is it not undefined behavior?

No, it's well-defined. It simply has different semantics to what you're expecting.

The expression is evaluated as follows:

if (((a[0] < a[1]) < a[2]) < a[3]) {

Each comparison produces a boolean ( 0 or 1 ) outcome.

The (boolean) result of a[0] < a[1] is compared to a[2] , and the (boolean) result of that comparison is compared to a[3] .

I am sure there are some legitimate use cases, but they are rare at best.

The correct way to express what you're trying to express is

if (a[0] < a[1] && a[1] < a[2] && a[2] < a[3]) {

It's not undefined behavior, it just doesn't do what you think it does. It's equivalent to

(((a[0] < a[1]) < a[2]) < a[3])

1 for true, 0 for false. So if a[0] is less than a[1], then it's comparing a[2] to 1, otherwise, to zero. And so on.

It's not undefined behavior , it's unexpected-to-you behavior .

In C and C++ you cannot do math-like comparisons like that. You can compare two things at a time. So, if you want a < b < c < d , you must write:

if (a < b && b < c && c < d)
    ...

Since you brought C++ into the mix, you could very simply do

if ( std::is_sorted(a, a+4) )
    puts("OK!");

It is defined behaviour, but doesn't do what you expect, so don't do that.

Your expression becomes:

((a[0] < a[1]) < a[2]) < a[3]

where each x < y is turned into either 1 or 0 - which means that it's ALWAYS true if a[3] is greater than 1, and possibly true if a[3] is greater than 0.

It isn't undefined behavior, but it doesn't do what he thinks it does. < is left-to-right associative, so first a[0] < a[1] is evaluted, resulting in true . Then true < a[2] (equivalent to 1 < a[2] ) is evaluated, resulting in true . And so on. You only got the right result by coincidence. For example, "2 1 0 1" would also yield true. Use either

a[0] < a[1] && a[1] < a[2] && a[2] < a[3]

or more generally, if your array is long:

for(i=1,ok=1;i<n&&ok;i++)ok &= a[i-1] < a[i];

The order of evaluation of the < operator, when appearing like this, is well-defined. The code you have written is equivalent to:

bool x;

x = a[0] < a[1];

if(x == true)
{
  x = true < a[2]; 
}
else
{
  x = false < a[2]; 
}

if(x == true)
{
  x = true < a[3]; 
}
else
{
  x = false < a[3]; 
}

if(x == true)
{
  printf("OK!\n");
}
else
{
  printf("I've told ya\n");
}

true always evaluates to the integer 1, false to 0. As you can tell, this code makes no sense at all.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM