【问题标题】:execution of ternary operator三元运算符的执行
【发布时间】:2017-12-06 01:35:18
【问题描述】:
#include <stdio.h>

#define max(x,y)(x)>(y)?x:y

int main() {
    int i = 10;
    int j = 5;
    int k = 0;
    k == max(i++, ++j);
    printf("%d%d%d ", i, j, k);
    return 0;
}

我知道答案。它是11 7 0,但如何?请帮我执行三元运算符。

【问题讨论】:

  • 使用带有副作用表达式的宏是一个的想法。不要永远编写这样的代码。注意:这与三元运算符无关。
  • MSVC 的 stdlib.h 已经有 max 宏 - 也许 gcc 也有。
  • 你确定 k == max(I++,++j) 吗? '==' 将检查 'k' > 0.
  • @IharobAlAsimi;那肯定不是 UB。
  • @Jean-FrançoisFabre:使用副作用参数很好。问题是如果副作用参数没有被精确评估一次。

标签: c macros operator-keyword ternary


【解决方案1】:

这个问题绝对是一个会抓住许多毫无戒心的 C 程序员的技巧问题。这里的不同响应者在 C 方面拥有超过 100 年的复合经验,但需要多次尝试才能做到这一点:

表达式k == max(i++, ++j); 扩展为:

k == (i++)>(++j)?i++:++j;

解析为this(==的优先级低于&gt;,但高于?):

     (k == ((i++) > (++j)))
     ? i++ 
     : ++j;

三元运算符评估测试(i++)&gt;(++j),这对于程序中的值是正确的,因此评估为1,与k的值不同,因此它继续评估第三个表达式j++ ,第二次递增j 并返回中间值6。测试和执行的分支之间有一个序列点,因此可以将j 递增两次。由于测试评估为假,因此根本不执行第二个分支。

i 增加一次,其值变为11

j 递增两次,其值为7

k没有被上述语句修改,因为==是比较运算符,而不是赋值运算符。

因此输出为11 7 0

注意事项:

该程序使用了一个宏max,它不止一次地评估它的参数,并且它们在展开式中没有正确括起来:2 个错误说明了宏的缺点。这个宏应该命名为MAX,以强调它的参数不应该有副作用,并且它的扩展应该用这种方式完全括起来:

#define MAX(x,y) ((x) > (y) ? (x) : (y))

更好的选择是使其成为内联函数:

static inline int max(int x, int y) {
    return x > y ? x : y;
}

如果程序有这样的语句:

k = max(i++, ++j);

输出将是 12 6 11,因为与 == 不同,= 的优先级低于 ?,因此该语句将扩展为:

k = ((i++) > (++j))
    ? i++ 
    : ++j;

您可以学习table of operator precedence for C。在我看来,关卡太多了,很难记住所有关卡,尤其是因为其中一些相当违反直觉:打印一份副本并放在手边或做一个书签。如有疑问,请使用括号。

【讨论】:

  • 表达式中没有UB。
  • @hacks: 是的,我改了答案,在测试和采取的分支之间有一个序列点。
  • 我已经在 gcc 上测试了代码,令我惊讶的是得到了与 OP 相同的结果
  • @Jean-FrançoisFabre:是的,我花了一段时间才发现== 的优先级高于?,而= 的优先级较低。
  • 我得到 11 7 0 作为答案。我在 geeksforgeeks.com 上的虚拟编译器上运行它
【解决方案2】:

声明

k==max(i++,++j);  

扩展为

k==(i++)>(j++)?i++:j++;  

注意==precedence?: 更高,因此上面的表达式等价于

( k == ((i++)>(j++)) )?i++:j++;  

由于(i++)&gt;(j++) 将是true,因此k == ((i++)&gt;(j++)) 被评估为false,因此j++(它的值变为7)将被评估(i++ 将被跳过)。


注意: 上面的表达式不会调用未定义的行为,因为在三元运算符的第一个操作数的计算与第二个或第三个操作数的计算之间存在sequence point。例如,表达式

a = (*p++) ? (*p++) : 0 

具有明确定义的行为。

【讨论】:

  • 10&gt;6false 吗?怎么样?
  • (10>6).怎么是假的?
  • @Abhijeetsingh;再次阅读答案。
  • 很好的答案。现在人们可能想知道如何编写这样的代码,或者哪些恶毒的老师会提出这样的问题。没用。
  • @Jean-FrançoisFabre;我们不得不承认,这是一个诡计的问题;)
【解决方案3】:

您使用的是双等号,这是一种比较。 k==max(i++,++j);将max的返回值与k进行比较,即0。

请尝试将== 更改为=

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-13
    • 1970-01-01
    • 2018-09-18
    • 2021-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-08
    相关资源
    最近更新 更多