【问题标题】:variable assignment in conditional after && (C) [duplicate]&&(C)之后的条件变量赋值[重复]
【发布时间】:2018-03-25 09:29:20
【问题描述】:

我很好奇 C 标准关于条件子句中变量赋值的确切定义。这是一个小例子:

int foo() {
  ...
}

int bar() {
  ...
}

int main () {
  int a, b, x, y;
  ...
  if ( (a = foo()) == x && (b = bar() == y ) {
    ...
  }
  ...
}

使用 GCC 的测试表明,如果 (a = foo()) != xb = bar() 将不会被执行。一方面,这种行为是最佳的,因为它不会浪费任何时间来计算bar()。但另一方面,b 的值有些不确定,因为它取决于foo() 的结果,而这实际上与b 无关。

我想知道 C 标准中是否有针对此类情况的明确定义,以及该定义的原因是什么。最后,编写此类代码的最佳实践是什么?

【问题讨论】:

  • 查找“短路评估”
  • 哪些情况?请详细说明。
  • 如果if之后的代码依赖于b被初始化,那么“最佳实践”就是不要那样做。
  • 请匹配括号。
  • 这个问题的一些味道之前在 SO 上被问过 100 次。请在发布之前做一些研究。对于无论如何回答的人,请关闭投票,可以在SO C tag wiki FAQ 中找到规范的欺骗列表。

标签: c conditional variable-assignment


【解决方案1】:

使用 GCC 的测试表明 if (a = foo()) != x, b = bar() 不会被执行。

嗯,这是逻辑 AND (&&) 运算符的属性。

引用C11,第 §6.5.13 章,强调我的

与按位二进制 & 运算符不同,&& 运算符保证从左到右的求值; 如果对第二个操作数求值,则在求值之间存在一个序列点 第一个和第二个操作数。 如果第一个操作数比较等于 0,则第二个 不计算操作数。

也就是说,对于b赋值,你是对的,如果第一个操作数是 FALSE,b 的值仍然是不确定的,并且该变量的任何使用都可能导致undefined behavior.

(其中之一)最佳实践,是在定义时初始化局部变量以避免使用不确定的值。

【讨论】:

    【解决方案2】:

    运算符&&短路计算组成:第二个子表达式只有在需要其结果时才被计算,以确定整个表达式的结果。


    在您的示例中,在表达式中:

    (a = foo()) == x && (b = bar() == y)
    

    如果第一个子表达式 (a = foo()) == x 的计算结果为 false,则无论子表达式 (b = bar() == y) 会产生什么结果,上述表达式的结果也是 false。

    由于短路评估和(a = foo()) == x 评估为假的事实,表达式(b = bar() == y) 永远不会被评估。

    【讨论】:

      【解决方案3】:

      这很简单:如果第一个参数的计算结果为 0,&& 的第二个(即右手)参数将被计算。

      因此,如果 (a = foo()) == x 为 0,(b = bar() == y )被评估。

      这可能会使b 未初始化(可能导致未定义的结果)这一事实是您不应该以这种方式编码这一事实的试金石。

      可以使用

      if ((a = foo() == x) & (b = bar() == y))
      

      如果您希望始终评估双方:& 未短路。但是,如果参数可以评估为 0 或 1 以外的值(在这种情况下不会),请注意意外的影响。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-26
        • 1970-01-01
        • 2017-07-01
        • 2013-09-13
        • 1970-01-01
        • 2013-07-14
        相关资源
        最近更新 更多