2

我想知道如何在 C/C++ 中处理多个条件。我有一些运行良好的代码,但我担心这涉及到运气因素,我不想被抓住。考虑:

if ( (/*condition1*/) || (/*condition containing invalid reference*/) )
{
    // do something
}

只要“条件 1”为 TRUE,即使条件本身会产生故障,第二个条件似乎也不会产生错误。例如:

int main()
{
    char    string1[] = "StackOverflow";
    char    *string2 = 0;

    // (1) This will work because string1 is valid
    if (strlen(string1) != 0)
        printf("%s", string1);

    // (2) This will cause an error
    if (strlen(string2) != 0)
        printf("%s", string2);

    // (3) But this if(OR) works fine
    if ((strlen(string1) != 0)||(strlen(string2) != 0))
        printf("no problem!");

    // (4) And of course this doesn't
    if ((strlen(string2) != 0)||(strlen(string1) != 0))
        printf("I don't believe it!");

    return 0;
}

从 OR 条件列表可以看出,if()“问题”在第一个 TRUE 语句处停止,从左到右阅读,无论后面是什么。但是,将数字 (3) 更改为:

if ((strlen(string1) == 0) && (strlen(string2) == 0)

尽管第一个条件为假,但仍然会失败,从而将整个事情呈现为假 - 即问题不会像 OR 示例那样停止。

概括地说,我观察到以下几点:

if ( (TRUE) or (INVALID) )   -> no problem

if ( (FALSE) or (INVALID) )  -> error

if ( (TRUE) and (INVALID) )  -> error

if ( (FALSE) and (INVALID) ) -> error    // see the EDIT

这些结果在所有情况下都是通用的,还是依赖于编译器/平台?

我可以按照上述规则编写代码,还是永远不要陷入其中一个条件无效的情况?

我正在为我的老板检查一些旧代码,其中充斥着上面 (3) 之类的示例。将它们全部捕获并调整代码以避免任何无效条件将需要相当长的时间。虽然(3)和(4)可以很容易地调整到一个if(string2 != 0) { // }块内,但对于我拥有的代码来说,在实践中并不是那么容易。

编辑:

由于再次检查,if ( (FALSE) and (INVALID) )确实运行没有错误。我不知道为什么它之前失败了;如果它最初有效,我什至可能都没有提出这个问题。我会把它归结为巫术和注意力不集中。

最终,虽然已经暗示了答案但没有逐字确认,但似乎这种对短路评估的依赖(感谢维基链接!)是一种合法的技术。我很高兴我不必重新编写任何代码!

4

4 回答 4

2

是的,这是众所周知的行为,它适用于任何遵循标准的 C/C++ 编译器。正如 Jesse 在他的评论中已经提到的那样,这被称为短路并且经常使用,尤其是指针:

void func( int *ptr )
{
   if( ptr && *ptr ) {
      // pointer is valid and integer that it points to is not 0
   }
}

你的最后一句话:

if ( (FALSE) and (INVALID) ) -> error

不正确。如果 left 为假,又名 && 将不会评估右操作数。

于 2013-02-23T20:35:09.887 回答
2

您所说的称为“短路”,它是c ++中的通用功能。它的工作方式是 (TRUE || any) 总是为真,因此一旦知道表达式为真,就不会进一步评估表达式。这同样适用(FALSE && any),因为这总是错误的。

这是如何有用的一个很好的例子:

int x = 0;
cin >> x;
if (x != 0 && 10 / x == 2) {
    // ...
}

通过对 x 的检查,如果用户输入 0,则不会出现 10 / 0,从而使您的程序免于除以 0。

您始终可以使用涉及 && 和 || 的表达式来依赖此功能。

于 2013-02-23T20:40:50.213 回答
0

在 C 和 C++ 中,一旦确定结果,它就会停止计算布尔表达式,|| 因此,运算符总是在某些东西返回 true 时立即停止评估,左侧部分优先,&& 在某些东西返回 false 时立即停止。

你可以把任何你想要的东西放在右边,它不会评估。

请记住,您将具有未定义行为的东西用作“无效”表达式,如果它起作用,则无法知道会发生什么。

于 2013-02-23T20:35:09.560 回答
0
    if (strlen(string2) != 0)
    printf("%s", string2);

这里string2不是字符串,因此strlen调用会调用未定义的行为。

if ((strlen(string1) != 0)||(strlen(string2) != 0))

在 C 中,||如果运算符的左操作数计算结果为 ,则保证运算符不会计算其右操作数1。这里的左操作数||计算结果为1so strlen(string2),这是未定义的行为,永远不会被调用。

于 2013-02-23T20:28:23.307 回答