首页 > 解决方案 > C中的三元运算符?

问题描述

为什么输出显示为 3?这背后的概念是什么?

#include <stdio.h>

int main()
{
    int a = 5, b = 4, c;
    c = a > b ? 1, 2, 3 : 2, 5, 6;
    printf("%d\n", c);
    return 0;
}

标签: c

解决方案


包含三元运算符的代码行错综复杂且耐人寻味。它的解释方式也有微妙但至关重要的不对称性,当它按照问题所示编写时,这些不对称性远非明显。让我们考虑如下原始代码的一个小变体,它同时使用三元运算符的“真”和“假”部分(在两个单独的语句中——尽管我可以创建一个函数并将参数传递给它):

#include <stdio.h>

int main(void)
{
    int a = 5, b = 4, c;
    c = a > b ? 1, 2, 3 : 2, 5, 6;
    printf("a = %d, b = %d, c = %d\n", a, b, c);
    a = b - 1;
    c = a > b ? 1, 2, 3 : 2, 5, 6;
    printf("a = %d, b = %d, c = %d\n", a, b, c);
    return 0;
}

该程序的输出是:

a = 5, b = 4, c = 3
a = 3, b = 4, c = 2

这里发生了什么?

请记住,逗号运算符的优先级甚至低于赋值运算符,因此您可以根据需要编写如下代码:

if (a > b)
    c = 2, d = 3, e = 6;

并且在语句的主体中有三个赋值if。这不会被视为一般用途的好代码,但该技术在宏中可能很有用 - 偶尔它可以在宏中有用。

让我们添加一些括号——编译器解释代码时的正确括号集:

 c =  a > b  ?  1, 2, 3  : 2 , 5, 6;
(c = (a > b) ? (1, 2, 3) : 2), 5, 6;

条件a > b控制是否评估1, 2, 32,并将结果分配给c。的结果1, 2, 33,所以如果a > b,分配的值是3(如问题),如果a <= b,分配的值是2。The5和 the6被评估为副作用 - 但没有副作用,因此它们被有效地丢弃。

三元运算符的对和:之间的代码有分组作用,不会出现在 之后。?::

请注意,要编译此代码,我必须放弃我的默认编译器选项。使用问题中的代码和我正常的默认编译器选项,我得到(源代码在top67.c):

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
>     top67.c -o top67 
top67.c:3:5: error: function declaration isn’t a prototype [-Werror=strict-prototypes]
 int main()
     ^~~~
top67.c: In function ‘main’:
top67.c:6:18: error: left-hand operand of comma expression has no effect [-Werror=unused-value]
     c = a > b ? 1, 2, 3 : 2, 5, 6;
                  ^
top67.c:6:21: error: left-hand operand of comma expression has no effect [-Werror=unused-value]
     c = a > b ? 1, 2, 3 : 2, 5, 6;
                     ^
top67.c:6:28: error: right-hand operand of comma expression has no effect [-Werror=unused-value]
     c = a > b ? 1, 2, 3 : 2, 5, 6;
                            ^
top67.c:6:31: error: right-hand operand of comma expression has no effect [-Werror=unused-value]
     c = a > b ? 1, 2, 3 : 2, 5, 6;
                               ^
cc1: all warnings being treated as errors
$

我会从这个答案中显示的代码中得到更多错误。您应该使用类似的选项进行编译以避免您自己的代码出现问题。


推荐阅读