【问题标题】:How to understand [], (), compound literal operator, . and -> are postfix operators?如何理解 [], (), 复合字面运算符, .和 -> 是后缀运算符吗?
【发布时间】:2018-01-24 15:43:53
【问题描述】:

在它自己的定义中,后缀运算符是在其所有操作数之后指定的运算符。

在 C11 标准中,后缀运算符定义为:

6.5.2 后缀运算符

语法

postfix-expression:

    primary-expression
    postfix-expression [ expression ]
    postfix-expression ( argument-expression-listopt )
    postfix-expression . identifier
    postfix-expression -> identifier
    postfix-expression ++
    postfix-expression --
    ( type-name ) { initializer-list }
    ( type-name ) { initializer-list , }
  1. 标准将.->前后两部分称为 操作数,我在以下引用中以粗体突出显示。这是否意味着.-> 实际上是中缀 运算符,尽管在 标准?

    6.5.2.3 结构和联合成员

    约束

    1 第一个操作数。操作员应有一个原子, 合格或不合格的结构或联合类型,以及第二个 操作数应命名该类型的成员。

    2 -> 运算符的第一个操作数 应具有类型 “指向原子的、合格的或不合格的结构的指针”或 “指向原子、合格或不合格联合的指针”,以及 第二个操作数应命名指向类型的成员。

  2. []() 和复合文字的小节没有提及 “操作数”这个词。所以

    • []() 都是一元后缀运算符,在它们前面有一个(函数)指针名称作为它们唯一的操作数,而 []() 里面的什么不是操作数?这就是the accpeted reply 所说的In a function call, what is the operator, and what are the operands?
    • 什么是复合文字的运算符,()(type-name) 或其他? {} 中的initializer-list 可能不是操作数,就像[] 中的数组索引和() 中的函数参数一样。 {} 可能不是运算符的一部分,因为它用于封装初始化程序。如果复合字面量的操作符是(type-name),复合字面量操作符不带任何操作数吗?
  3. 虽然强制转换运算符不是 C 中的后缀运算符,但它看起来几乎是 与复合文字运算符相同。

    6.5.4 转换运算符语法

    cast-expression:
    
        unary-expression
        ( type-name ) cast-expression
    

    约束 2 除非类型名称指定 void 类型,否则类型名称 应指定原子的、合格的或不合格的标量类型,并且 操作数应为标量类型。

    演员运算符 ()(type-name) 也是如此吗?是它的操作数 cast-expression,或者type-namecast-expression

谢谢。

【问题讨论】:

  • 认为 C 标准甚至没有指定后缀运算符,只有后缀表达式。跨度>
  • 语言律师问题可能很有趣。但是你最新的好像是“Is an expression an expression”的形式?
  • 该标准在任何地方都没有提到“复合文字运算符”,所以我不愿意称它为运算符,即使它位于“后缀运算符”部分。相反,“复合文字”只是一个“后缀表达式”。
  • @Tim:语言定义中所说的它们是什么。 [] 运算符的操作数是数组表达式和索引。 () 运算符的操作数是函数表达式和参数表达式。 .-> 运算符的操作数是struct(或struct 指针)表达式和成员名称。它们与后缀 ++-- 运算符混为一谈,以确保它们都具有相同的优先级。

标签: c operators expression language-lawyer


【解决方案1】:
  1. 语言规范定义了语法,并不关心组成语言的部分是什么。

    abc->def中,第一个操作数是abc->是运算符,def是第二个操作数,但仅限于标识符是结构或联合成员的名称第一个操作数(可能是成熟的postfix-expression)标识的类型。您不能在 -> 运算符的 RHS 上编写通用表达式 — abc->3 不起作用,abc->(x + y) 也不起作用。类似的 cmets 也适用于 . 运算符,比照适用。

    如果您想将其视为中缀运算符,您可以这样做。那是你的特权。它不会帮助您理解标准。

  2. (a) [] 运算符遵循后缀表达式;它在后缀表达式之后;这使它成为一个后缀运算符。
    (b) () 函数调用运算符跟在后缀表达式之后;它在后缀表达式之后;这使它成为一个后缀运算符。
    (c) 复合字面量运算符是(type){} 的全部。由于{ … } 出现在(type) 部分之后,并且由于它在语法中的行为与其他后缀运算符一样,因此将其视为后缀运算符是合理的。标准说它是一个;反正真的没关系。语言按指定工作。

  3. 强制转换运算符是单独分组的,是一种“前缀运算符”。它们与复合文字不同。强制转换后的表达式不能以 { 开头;复合文字中“转换符号”之后的文字只能以{ 开头。 { 的存在与否决定了构造是强制转换还是复合文字。

如果您阅读并理解该标准,所有这些都非常明显。


  1. (a) 和 (b) C 标准并没有说“它在后缀表达式之后;这使它成为后缀运算符”。我也不确定那是什么意思。通常在 C 之外,如果一个运算符出现在其所有操作数之后,则称为后缀。

标准规定构建后缀表达式的方法之一是:

后缀表达式 [ 表达式 ]

从我现在的位置来看,[] 运算符跟在一个后缀表达式之后;它在后缀表达式之后;这使它成为一个后缀运算符” 似乎对该部分的描述相当准确的语法。 [] 出现在前面的 postfix-expression 之后。我不确定“后缀运算符”比“在某事之后出现的运算符”还能理解什么,而[] 在“某事”之后。

2(c) 到目前为止,我阅读 C 书籍的直觉表明,初始化部分不是操作数或运算符,所以我怀疑 {} 是复合文字运算符的一部分。

复合字面量由括在圆括号(圆括号)中的类型名称和括在花括号(大括号)中的初始化列表组成。制作复合文字需要所有这些。我不明白{} 怎么不能成为复合文字的一部分——语法说它是,而且……好吧,如果你想把它看作是单独的东西,我不能阻止你,但是你'这样做会让你自己的生活变得更加困难,并使那些试图帮助你的人的生活变得非常困难。从我屏幕的这一侧看,你真的不清楚你是如何想出这些新方法来如此巧妙而狡猾地误解标准的纯文本。

【讨论】:

  • 谢谢。我投了赞成票,尽管该标准并没有解决我的困惑。因此,它不像“如果您阅读并理解标准,所有这些都非常明显”。我更新了我的帖子以解释更多。 1.不是我“调用构成语言的部分”,而是标准在.之后调用这些部分。和-> 作为第二个操作数。
  • 2. (a) 和 (b) C 标准没有说“它在后缀表达式之后;这使它成为后缀运算符”。我也不确定那是什么意思。通常在 C 之外,如果一个运算符出现在其所有操作数之后,则称为后缀。 2(c) 到目前为止,我阅读 C 书籍的直觉表明,初始化部分不是操作数或运算符,所以我怀疑 {} 是复合文字运算符的一部分。
  • 我怀疑。但是您对此的回答更有意义。所以我倾向于将{} 视为复合文字运算符的一部分。
  • 标准说操作符是一个标点符号,它指定要执行的操作,而"other forms of operator also exist in some contexts"。也许复合文字的符号应该被认为属于这个类。
【解决方案2】:

编辑

我的睡眠有点不足,再加上咖啡喝多了,所以我的心理过程没有尽可能清晰地运作,因此我最初的反应中出现了混乱的污泥。

这些运算符被称为“后缀运算符”,因为它们遵循后缀表达式,而不是因为它们的操作数的数量或位置。类似地,前缀运算符被称为“一元运算符”,因为它们位于 unary-expression 之前。 “强制转换运算符”在 cast-expression 之前,“乘法运算符”在 multiplicative-expressions 之后,依此类推。 IOW,运算符以其适用的表达式类型命名,不是因为运算符的内在属性。

原创

你在一定程度上想太多了。

()[].-> 和复合文字与后缀 ++-- 分组的主要原因是确保它们都具有相同(最高级别)优先级; &a[i]*f(x)a + b->c 等表达式都解析&(a[i])*(f(x))a + (b->c)。如果您坚持对其含义持迂腐态度,那么选择“后缀”一词来描述这些运算符是很不幸的,但它在上下文中有点意思。它们被称为“后缀运算符”的主要原因是它们遵循后缀表达式,而不是因为操作数的数量或位置。

语言标准大部分写得好且精确,但在某些方面可能会更好。这可能是这些领域之一。


  1. 请注意,标准使用“一元”而不是“前缀”来描述前导 *&++--sizeof 运算符,甚至尽管他们比后缀运算符更接近前缀运算符的概念。同样,这是因为这些运算符在 unary-expression 之前,而不是因为操作数的数量或位置。

【讨论】:

    猜你喜欢
    • 2022-11-24
    • 1970-01-01
    • 2022-07-13
    • 1970-01-01
    • 2021-04-20
    • 2020-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多