来自http://en.cppreference.com/w/cpp/language/operator_precedence的 C++ 运算符优先级表(我知道这不是规范的,但标准没有讨论优先级或关联性)将一元运算符标记为右/左关联.
从对不同问题的讨论中,我留下了疑问。一元运算符具有关联性是否有意义?
来自http://en.cppreference.com/w/cpp/language/operator_precedence的 C++ 运算符优先级表(我知道这不是规范的,但标准没有讨论优先级或关联性)将一元运算符标记为右/左关联.
从对不同问题的讨论中,我留下了疑问。一元运算符具有关联性是否有意义?
这只是关联性从语法中得出的方式的人工制品。
加法是左结合的原因是加法表达式的产生之一是加法表达式+乘法表达式,左边是加法表达式。所以当你看到:
a + b + c
this 必须等价于,因为匹配产生式的(a + b) + c
唯一方法是 witha + b
作为加法表达式和乘法表达式。它本身是一个加法表达式,但不是一个乘法表达式,因此如果我们尝试将其作为加法表达式,则它与产生式不匹配。c
a
b + c
a + b + c
a
如果你以前没有,我建议你通读“表达式”一章,忽略语义:只看语法产生式。然后你会看到语法是如何定义优先级和关联性的。大技巧是每个“高优先级”类型的表达式都是“低优先级”类型的表达式。因此,每个乘法表达式都是加法表达式,但反之亦然,这就是乘法比加法“绑定更紧密”的原因。
前缀一元运算符在语法中定义,例如:unary-expression : ++ cast-expression等,左侧的运算符用于前缀,右侧的运算符用于后缀。换句话说,我们在左侧“插入括号”作为后缀,在右侧“插入括号”作为前缀。也就是说,我们可以说后缀运算符的分组是从左到右的,前缀运算符的分组是从右到左的。事实上,C++ 标准正是这样说的(C++03 中的 5.2/1 和 5.3/1)。将这种一元分组称为“关联性”可能是对术语的滥用,或者至少是一种新造词。但这不是一个主要的,因为很明显必须是什么意思。
二元运算符和一元运算符之间的唯一区别是,如果二元运算符按相反方向分组,则语法仍然有意义,因此a - b - c
意味着a - (b - c)
. 这会令人惊讶,但不会影响语言。对于一元运算符,将 as 分组是非常令人惊讶的!!a
,(!!)a
该语言还必须为 sub-expression提供含义!!
,而目前它还没有。函数式语言可以赋予它一个含义:!!
可能意味着由!
和组成的函数!
,即与 相同的操作static_cast<bool>()
,但 C++ 没有组合函数或运算符的概念。C++ 不需要提供该含义的原因是!
“从右到左的组”。哪个(因为语法中的大技巧)只是另一种说法,!!
它不是语法正确的表达式,所以永远不是任何东西的子表达式。
所以是的,说前缀运算符从右到左分组并且后缀运算符从左到右分组是有道理的。但是,由于我们对 C++ 语言的其他了解,它必须是这样的,这也是“显而易见的”。
顺便说一句,我认为至少从技术上讲,在 C++ 中,后缀不是++
一元运算符。它是一个后缀运算符。但这真的无关紧要,只是它是标准中的术语,因为显然它是一个运算符并且它有一个操作数,所以英语中的“一元”也是如此。
在一元运算符的情况下,运算符的关联性仅决定了运算符出现在操作数的哪一侧。
考虑以下代码
int *p;
*p++;
表达式*p++
可以被评估为(*p)++
(递增 p 指向的对象)或*(p++)
(指向 p 指向的下一个对象)。
因为一元运算符是右结合的,所以表达式*p++
将被计算为*(p++)
。(我在阅读Kernighan 和 Ritchie时想到了这个。)
似乎优先级和关联性已更改,并且后缀++
的优先级高于取消引用*
运算符。
根据 C11,上述表达式将被评估为*(p++)
。
我希望这可以更清楚地说明为什么一元运算符具有关联性。
感谢Lucian Grigore指出这一点。
不确定,但如果以下内容有效,则可以。
++i--
但事实并非如此,并引发错误
lvalue required as increment operand
一元运算符的所有行为只能用优先级来解释。