为什么 'dereference' 和 'address of' 运算符在左边?

Why are the 'dereference' and the 'address of' operators on the left?

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

*ptr->field

*arr[id]

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

ptr*->field vs ptr->field*

arr*[id] vs arr[id]*

那么运算符 一元而不是右是否有充分的理由。我想到的一件事是类型声明。左运算符留在类型名称附近(char *a vs char a*),但是有类型声明,这已经打破了这个规则,所以为什么还要费心(char a[num]char (*a)(char) 等).

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

 val*=2

这将是 val = val * 2*= 简写或取消引用并分配 val* = 2。 然而,在取消引用的情况下,通过在 *= 标记之间要求一个白色 space 可以很容易地解决这个问题。再一次,没有什么开创性的,因为有这样一个规则的先例(- -a vs --a)。

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

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

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

An accident of syntax contributed to the perceived complexity of the language. The indirection operator, spelled * in C, is syntactically a unary prefix operator, just as in BCPL and B. This works well in simple expressions, but in more complex cases, parentheses are required to direct the parsing. For example, to distinguish indirection through the value returned by a function from calling a function designated by a pointer, one writes *fp() and (*pf)() respectively. The style used in expressions carries through to declarations, so the names might be declared

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

In more ornate but still realistic cases, things become worse:

int *(*pfp)();

is a pointer to a function returning a pointer to an integer. There are two effects occurring. Most important, C has a relatively rich set of ways of describing types (compared, say, with Pascal). Declarations in languages as expressive as C—Algol 68, for example—describe objects equally hard to understand, simply because the objects themselves are complex. A second effect owes to details of the syntax. Declarations in C must be read in an `inside-out' style that many find difficult to grasp [Anderson 80]. Sethi [Sethi 81] observed that many of the nested declarations and expressions would become simpler if the indirection operator had been taken as a postfix operator instead of prefix, but by then it was too late to change.


所以*C的左边是因为on the left in B.

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

a!b

is equivalent to !(a+b).

!a

is the content of the cell whose address is given by a; it can appear on the left of an assignment.

然而,已有 50 年历史的 BCPL 手册甚至没有提及 ! 运算符 - 相反,运算符是单词:一元 lvrv .由于这些被理解为好像它们是函数,所以很自然地它们先于操作数;后来较长的 rv a 可以用语法糖 !a.

代替

许多当前的 C 运算符实践都可以通过这条路线进行追踪。 B alike a[b] 相当于 *(a + b)*(b + a)b[a] 就像在 BCPL 中可以使用 a!b <=> b!a.

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

所以一元 * 在 C 中位于左侧的原因与 一样无聊“在更简单的程序中,一元 * 没有任何问题在左边,在每个人都习惯于使用其他语言的取消引用运算符的情况下,没有人真正认为其他方法会更好,直到为时已晚才改变它.