6

我告诉我的一个朋友(正在学习 C)他不能同时进行多个变量比较:

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");

    }

}

所以,为了证明我是对的,我已经编写了上面的程序,然后我用1 2 3 4. 令人惊讶的是它打印出来了OK!。所以我不知道该告诉他什么,因为我确信这是不对的。

最后,它是还是不是未定义的行为?

4

7 回答 7

12

不,它是明确定义的。它只是具有与您所期望的不同的语义。

表达式计算如下:

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

每次比较都会产生一个布尔 (01) 结果。

的(布尔)结果与a[0] < a[1]进行比较a[2],并且该比较的(布尔)结果与 进行比较a[3]

我确信有一些合法的用例,但充其量是很少见的。

表达你想要表达的正确方式是

if (a[0] < a[1] && a[1] < a[2] && a[2] < a[3]) {
于 2013-01-30T20:32:28.233 回答
4

这不是未定义的行为,它只是没有做你认为它做的事情。相当于

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

1为真,0为假。因此,如果 a[0] 小于 a[1],则将 a[2] 与 1 进行比较,否则将其与零进行比较。等等。

于 2013-01-30T20:32:42.737 回答
4

这不是未定义的行为,而是出乎意料的行为

在 C 和 C++ 中,您不能进行类似数学的比较。您可以一次比较两件事。所以,如果你想a < b < c < d,你必须写:

if (a < b && b < c && c < d)
    ...
于 2013-01-30T20:34:26.217 回答
3

由于您将 C++ 纳入其中,因此您可以非常简单地做

if ( std::is_sorted(a, a+4) )
    puts("OK!");
于 2013-01-30T20:49:12.683 回答
2

这是已定义的行为,但不会按照您的预期做,所以不要那样做。

你的表达变成:

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

其中每个 x < y 都变成 1 或 0 - 这意味着如果 a[3] 大于 1,则它始终为真,如果 a[3] 大于 0,则可能为真。

于 2013-01-30T20:33:56.317 回答
2

这不是未定义的行为,但它并没有像他认为的那样做。< 是从左到右关联的,因此首先a[0] < a[1]评估,导致true. 然后true < a[2](等价于1 < a[2]) 被评估,结果是true。等等。你只是巧合地得到了正确的结果。例如,“2 1 0 1”也会产生真值。使用任一

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

或更一般地说,如果您的数组很长:

for(i=1,ok=1;i<n&&ok;i++)ok &= a[i-1] < a[i];
于 2013-01-30T20:36:03.257 回答
1

< 运算符的求值顺序,当这样出现时,是明确定义的。您编写的代码相当于:

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 始终计算为整数 1,false 为 0。如您所知,这段代码毫无意义。

于 2013-01-30T20:43:54.943 回答