为什么左侧的'dereference'和'address of'运算符在左侧? [英] Why are the 'dereference' and the 'address of' operators on the left?

查看:120
本文介绍了为什么左侧的'dereference'和'address of'运算符在左侧?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In C (and some other C-like languages) we have 2 unary operators for working with pointers: the dereference operator (*) and the 'address of' operator (&). They are left unary operators, which introduces an uncertainty in order of operations, for example:

*ptr->field

*arr[id]

操作顺序 由标准严格定义,但是从人的角度来看,这令人困惑.如果*运算符是 right 一元运算符,则顺序将是显而易见的,并且不需要多余的括号:

The order of operations is strictly defined by the standard, but from a human perspective, it is confusing. If the * operator was a right unary operator, the order would be obvious and wouldn't require extra parentheses:

ptr*->field vs ptr->field*

arr*[id] vs arr[id]*

所以有充分的理由说明为什么运算符 left 一元,而不是right.我想到的一件事就是类型的声明.左运算符停留在类型名称(char *achar a*)附近,但是有类型声明已经破坏了该规则,所以为什么要打扰(char a[num]char (*a)(char)等).

So is there a good reason why are the operators left unary, instead of right. One thing that comes to mind would be the declaration of types. Left operators stay near the type name (char *a vs char a*), but there are type declarations, which already break this rule, so why bother (char a[num], char (*a)(char), etc).

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

Obviously, there are some problems with this approach too, like the

 val*=2

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

Which would be either an *= short hand for val = val * 2 or dereference and assign val* = 2. However this can be easily solved by requiring a white space between the * and = tokens in case of dereferencing. Once again, nothing groundbreaking, since there is a precedent of such a rule (- -a vs --a).

那为什么为什么要用左运算符而不是右运算符呢?

So why are they left instead of right operators?

我想指出的是,我问了这个问题,因为C的许多怪异方面都有有趣的解释,如

I want to point out, that I asked this question, because many of the weirder aspects of C have interesting explanations, for why they are the way they are, like the existence of the -> operator or the type declarations or the indexing starting from 0. And so on. The reasons may be no longer valid, but they are still interesting in my opinion.

推荐答案

确实是的权威来源::

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

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)();

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

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 左侧的原因是因为它是


Thus the reason why * is on the left in C is because it was on the left in B.

B 部分基于 BCPL ,其中取消引用运算符为!. 在左边二进制!数组索引运算符:

B was partially based on BCPL, where the dereferencing operator was !. This was on the left; the binary ! was an array indexing operator:

a!b

等效于!(a+b).

!a

是其地址由a给出的单元格的内容;它可以显示在作业的左侧.

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

然而,已有50年历史的 BCPL 手册没有" t甚至包含对!运算符的提及-相反,这些运算符是单词:一元lvrv.由于这些被理解为好像是函数,因此很自然地将它们放在操作数之前.后来,长的rv a可以用语法糖!a代替.

Yet the 50 year old BCPL manual doesn't even contain mentions of the ! operator - instead, the operators were words: unary lv and rv. Since these were understood as if they were functions, it was natural that they preceded the operand; later the longish rv a could then be replaced with syntactic sugar !a.

许多当前的C运算符实践都可以通过此途径进行跟踪. B的a[b]等效于*(a + b)*(b + a)b[a],就像在BCPL中一样,可以使用a!b< => b!a.

Many of the current C operator practices can be traced via this route. B alike had a[b] being equivalent to *(a + b) to *(b + a) to b[a] just like in BCPL one could use a!b <=> b!a.

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

Notice that in B variables were untyped, so certainly similarity with declarations could not have been the reason to use * on the left there.

因此,一元代码*在C中位于左侧的原因与一样无聊.在一元代码*位于左侧的较简单程序中,没有任何问题,每个人都习惯于使用其他语言的解引用运算符,没有人真的认为其他方法会更好,直到更改它为时已晚." .

So the reason for unary * being on the left in C is as boring as "there wasn't any problem in the simpler programs with the unary * being on the left, in the position that everyone was accustomed to have the dereferencing operator in other languages, that no one really thought that some other way would have been better until it was too late to change it".

这篇关于为什么左侧的'dereference'和'address of'运算符在左侧?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆