【问题标题】:Why are the 'dereference' and the 'address of' operators on the left?为什么“取消引用”和“地址”运算符在左侧?
【发布时间】:2018-03-27 08:24:06
【问题描述】:

在 C(和其他一些类似 C 的语言)中,我们有 2 个用于处理指针的一元运算符:解引用运算符 (*) 和“地址”运算符 (&)。它们是一元运算符,它在运算顺序上引入了不确定性,例如:

*ptr->field

*arr[id]

操作顺序由标准严格定义的,但是从人类的角度来看,它是令人困惑的。如果 * 运算符是 right 一元运算符,则顺序很明显,不需要额外的括号:

ptr*->field vs ptr->field*

arr*[id] vs arr[id]*

那么,为什么运算符 left 是一元的,而不是右的,有充分的理由吗?想到的一件事是类型的声明。左运算符位于类型名称附近(char *achar a*),但有些类型声明已经违反了此规则,所以何必麻烦(char a[num]char (*a)(char) 等)。

显然,这种方法也存在一些问题,例如

 val*=2

这将是 *= 的简写 val = val * 2 或取消引用并分配 val* = 2。 然而,这可以通过在取消引用的情况下要求 *= 标记之间的空格来轻松解决。再一次,没有什么突破性的,因为有这样一条规则的先例(- -a vs --a)。

那么为什么他们是左而不是右运算符?

编辑: 我想指出,我问了这个问题,因为 C 的许多奇怪的方面都有有趣的解释,为什么它们是这样的,比如 existence of the -> operator 或类型声明或从 0 开始的索引。很快。原因可能不再有效,但在我看来它们仍然很有趣。

【问题讨论】:

  • 你想重写 C 语法吗?
  • @RuRo:毫无疑问是有原因的 :) 但这可能只是最初创建该语言的人的偏好。
  • 可能的罪魁祸首已经死了 6 年,R.I.P.
  • “为什么这种语言的设计者决定使用这种语法而不是其他同样可能的语法”类型的问题是无法回答的。
  • @n.m.如果你能逐字引用设计师的话,他们会非常负责任。

标签: c pointers syntax dereference operator-precedence


【解决方案1】:

确实权威来源:"The Development of the C Language" by the creator of the language, Dennis M. Ritchie:

语法上的意外导致了语言的复杂性。间接运算符,在 C 中拼写为 *,在语法上是一元前缀运算符,就像在 BCPL 和 B 中一样。这在简单表达式中效果很好,但在更复杂的情况下,需要括号来指导解析。例如,为了区分通过函数返回值的间接调用与调用由指针指定的函数,可以分别写入*fp()(*pf)()。表达式中使用的样式会延续到声明中,因此可以声明名称

int *fp();
int (*pf)();

在更华丽但仍然现实的情况下,情况会变得更糟:

int *(*pfp)();

是一个指向返回整数指针的函数的指针。有两种影响发生。最重要的是,C 有一组相对丰富的描述类型的方法(例如,与 Pascal 相比)。像 C 语言这样富有表现力的语言(例如 Algol 68)中的声明描述了同样难以理解的对象,仅仅是因为对象本身很复杂。第二个影响归因于语法的细节。 C 中的声明必须以许多人难以掌握的“由内而外”的风格阅读 [Anderson 80]。 Sethi [Sethi 81] 观察到,如果将间接运算符作为后缀运算符而不是前缀,许多嵌套的声明和表达式会变得更简单,但 到那时改变已经太迟了。


因此*C的左边是因为它是on the left in B

B 部分基于BCPL,其中解引用运算符为!。 这是在左边;二进制 ! 是一个 数组索引 运算符:

a!b

相当于!(a+b)

!a

是地址由a给出的单元格的内容;它可以出现在作业的左侧。

然而,已有 50 年历史的 BCPL 手册甚至没有提及 ! 运算符 - 相反,运算符是单词:一元 lvrv。由于这些被理解为好像它们是函数,它们自然位于操作数之前。稍后可以将较长的 rv a 替换为语法糖 !a


许多当前的 C 运算符实践都可以通过这条路线进行追踪。 B 有 a[b] 等价于 *(a + b)*(b + a)b[a] 就像在 BCPL 中一样可以使用 a!b b!a

请注意,B 中的变量是无类型的,因此与声明的相似性肯定不是在左侧使用* 的原因。

所以在 C 语言中,一元 * 位于左侧的原因就像 “在更简单的程序中没有任何问题,一元 * 位于左侧,位于每个人都习惯于在其他语言中使用取消引用运算符,没有人真正认为其他方式会更好,直到更改它为时已晚”

【讨论】:

  • 请注意,“=+”和“=*”的语法已更改为“+=”和“*=”。除法后取消引用也需要空格:“/ *ptr2var”与“/*ptr2var”(这将是评论的开始)。
  • “改变太晚了”可能确实是这样,但随着时间的推移,C 已经经历了语法添加。因此,可能很容易添加另一个操作符,该操作符的操作方式与另一个操作符相同,但采用后缀方式。有点可能不值得付出努力。
  • @glglgl 好吧,dmr 自己认为“为时已晚”; ANSI 和 ISO 委员会的方法都很保守。
  • 如果变量没有类型化,那么b * + 2b 乘以+2,还是取消引用-b 加2?
  • @M.M 是的,但是* 的选择在这里无论如何都是非常随意的。
猜你喜欢
  • 2014-01-12
  • 2012-01-20
  • 2012-06-04
  • 2014-03-23
  • 1970-01-01
  • 1970-01-01
  • 2019-12-27
  • 1970-01-01
  • 2016-03-13
相关资源
最近更新 更多