【问题标题】:Why ternary operator does not support blocks?为什么三元运算符不支持块?
【发布时间】:2015-09-26 20:09:32
【问题描述】:

为什么三元运算符没有块?换句话说,为什么下面的代码不起作用并报告{}大括号的错误?

int main()
{
    int i = 1;
    (i==1)?{printf("Hello\n")}:{printf("World\n")};
    return 0;
}

编辑

也许这个问题被误解了。它是:为什么不支持块?为什么只有一个表达式?

为什么不允许这样做?

int main()
{
    int i = 1;
    (i==1)?{printf("Hello\n");printf("World\n");}:{printf("Bye\n");printf("World\n");};
    return 0;
}

一个原因可能是三元常用于左侧的条件赋值,而块将没有这样的返回,或者它会与块内的多个语句混淆。

【问题讨论】:

  • 因为需要返回一个值。但是GCC可以这样(i==1)?({printf("Hello\n");}:({printf("World\n");});
  • 如果您的意图是使用多个语句,您可以在三元运算符中使用函数调用
  • 因为这是对三元运算符的糟糕使用。
  • 我认为编译器只允许一个表达式可能是因为两个原因.. 1. 它将它理解为布尔或 1/0 表达式 & 多个语句可能会妨碍 2. 这对可读性..为此我们有 if-else 我猜它更具可读性
  • @BLUEPIXY,我的 gcc 编译器不喜欢发布的代码,也不喜欢你的示例行。除其他外,此警告:“... ISO C 禁止在表达式 [-Wpedantic] 中使用大括号组”

标签: c language-lawyer ternary-operator


【解决方案1】:

三元运算符由表达式组成。没有这种使用大括号的表达式。

你可以简单地写

( i == 1 ) ? printf("Hello\n") : printf("World\n");

似乎在表达式中可以出现大括号的唯一情况是使用复合文字。例如

struct A { int x; int y; } a = { 1, 2 };

a = a.x < a.y ? ( struct A ){ a.y, a.x } : ( struct A ){ ++a.x, --a.y }; 

至于这个说法

(i==1)?{printf("Hello\n");printf("World\n");}:{printf("Bye\n");printf("World\n");};

然后可以使用逗号运算符重写如下方式

i == 1 ? ( printf("Hello\n"), printf("World\n") ) : ( printf("Bye\n"), printf("World\n") );

甚至喜欢

i == 1 ? printf("Hello\n"), printf("World\n") : ( printf("Bye\n"), printf("World\n") );

如果您需要代码块,请简短回答您的问题,然后使用 if-else 语句而不是三元运算符。虽然if-else 语句可能不能在表达式中使用。另一方面,为了代码的可读性,表达式不会太复杂。

与任何运算符一样,三元运算符用于表达式并返回一些评估值。例如,作为表达式,它可以用作初始化器或赋值。

【讨论】:

  • 复合文字运算符() {}怎么样?
  • @ouah 谢谢。我包含了一个使用复合文字的示例。
  • 用于提及复合文字 +1。
【解决方案2】:

是的,三元运算符中只能有一个表达式。您必须将if-else 用于多个语句。三元运算符仅在每个槽中采用一个表达式 虽然你可以在三元运算符中调用两个不同的函数

#include <stdio.h>

void a(){
 printf("Hello\n");
 printf("Hi\n");

}

void b(){
  printf("Hi\n");
  printf("Hello\n");
}

int main()
 {
int i = 1;
(i == 1) ? a() : b();
return 0;
}

【讨论】:

  • 实际上完全允许 ​​no 声明。正如您已经写的那样,只允许 表达式。原因很简单:它是一个运算符,因此它也“只是”一个表达式。
【解决方案3】:

三元运算符要求每个部分都有一个表达式,而{...} 不是表达式,而是语句。

为了扩展您的编辑,三元运算符的结果是一个表达式(但不是您建议的左值),并且语句块不能评估为一个值。

例如,这没有意义:

int x = (i==1)?{printf("Hello\n");printf("World\n");}:{printf("Bye\n");printf("World\n");};

但你可以这样做:

int x = (i==1)?(printf("Hello\n"), printf("World\n")):(printf("Bye\n"), printf("World\n"));

在这种情况下,逗号运算符将导致返回每个子表达式中的最后一个值。

【讨论】:

  • 要返回的每个子表达式中的最后一个值?但我得到的是Hello World 而不是World World。我理解错了吗?
  • @InsaneCoder 注意第二个“操作数”,因为x 将是 TRUE。
  • 因为三元运算符的条件部分为真,所以只计算第二部分。所以printf("Hello\n")printf("World\n")都运行了,后者的返回值会赋值给x
【解决方案4】:

引用C11标准,第§6.5.15章,条件运算符的语法是

conditional-expression:
    logical-OR-expression
    logical-OR-expression ? expression : conditional-expression

其中,第二个和第三个操作数是expression,而不是语句。

只是为了详细说明,

第二个和第三个操作数应满足以下条件之一:
— 两个操作数都有算术类型;
— 两个操作数具有相同的结构或联合类型;
— 两个操作数都有 void 类型;
— 两个操作数都是指向兼容类型的合格或不合格版本的指针;
— 一个操作数是指针,另一个是空指针常量;或
— 一个操作数是指向对象类型的指针,另一个是指向限定或 无效的不合格版本。


编辑:

回答问题

为什么只有一个表达式?

再次引用标准,

....结果是第二个或第三个操作数的值(以评估的为准),转换为下面描述的类型。

语句块,不会给出。一个expression的评价就可以了。

【讨论】:

    【解决方案5】:
    C语言中的

    运算符只能用在表达式中。表达式中没有“块”之类的东西。在 C 语言中,blocks 是高级句法结构的元素。块存在于语句级别。表达式可以在语句中使用。但是语句不能成为表达式(或在表达式中使用)。

    您的特定示例可以用表达式重写

    i == 1 ?
      printf("Hello\n"), printf("World\n") :
      printf("Bye\n"), printf("World\n");
    

    不需要{}

    (有关更多信息,请参阅Uses of C comma operator

    【讨论】:

    • @AnT 条件运算符的使用错误。看我的回答。:)
    【解决方案6】:

    三元运算符不打算用作控制结构,这意味着它不打算控制语句的执行。它只是一种选择将评估两个或多个表达式中的哪一个的方法。

    正如 Sourav Ghosh 所展示的,条件表达式的语法根本不允许 ?: 运算符的操作数是语句。

    【讨论】:

      【解决方案7】:

      这是不允许的,因为它没有意义。三元运算符旨在返回一个值。 {} 块会是什么? 然后还有另一个构造 if () { } else { } 已经用于与您尝试提供给 ? : 相同的目的。这不是比你发布的代码好看吗?

      int main(void)
      {
          int i = 1;
          if (i==1) {
             printf("Hello\n");
             printf("World\n");
          } else {
             printf("Bye\n");
             printf("World\n");
          };
          return 0;
      }
      

      【讨论】:

        【解决方案8】:

        正如其他人所指出的,GCC 允许在语法上将语句用作表达式,但这样的特性不是 C 标准的一部分。从历史上看,其原因可能与允许语句声明变量的事实有关,并且许多系统使用相同的堆栈来保存局部变量和参数,因为用于保存表达式评估中使用的临时值。允许新变量在语句的执行过程中存在,同时仍然保留旧变量,这会给编译器增加一些复杂性[注意,当在新表达式中调用函数时,会为该函数创建新变量,但是在被调用的函数返回并且新变量被销毁之前,旧值将“看不见”。

        话虽如此,C 的其他特性(例如可变长度数组)比在表达式中嵌入语句的能力需要的复杂性要高得多,因此支持该设计的论点不再像在1970 年代。不幸的是,即使今天的编译器的设计考虑与 1970 年代的不同,但某些东西曾经是不包含语言功能的令人信服的理由,这可能会导致它永远被认为是这样。

        【讨论】:

          猜你喜欢
          • 2016-06-24
          • 1970-01-01
          • 1970-01-01
          • 2013-07-30
          • 1970-01-01
          • 1970-01-01
          • 2021-04-28
          • 1970-01-01
          • 2015-10-07
          相关资源
          最近更新 更多