Why are operators "left" and "addresses" on the 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 remain unary operators, which leads to uncertainty in the order of operations, for example:

 *ptr->field 

or

 *arr[id] 

The order of operations is strictly defined by the standard, but from a human point of view it is confused. If the * operator was the correct unary operator, the order would be obvious and would not require additional brackets:

 ptr*->field vs ptr->field* 

and

 arr*[id] vs arr[id]* 

So, there is a good reason why operators remained unary rather than right. One thing that comes to mind is type declaration. Left operators remain next to the type name ( char *a vs char a* ), but there are type declarations that already violate this rule, so why bother ( char a[num] , char (*a)(char) , etc. .).

Obviously, there are some problems with this approach, such as

  val*=2 

This will be either a short hand *= for val = val * 2 , or dereferencing and assigning val* = 2 . However, this can be easily solved by requiring a space between the * and = tokens in case of dereferencing. And again, nothing happened, since there is a precedent for such a rule ( - -a vs --a ).

So why did they stay in place of the correct operators?

Edit: I want to point out that I asked this question because many of the stranger aspects of C have interesting explanations, because they are like existence -> or declarations of type or indexing, starting from 0. And so on. The reasons may be more invalid, but they are still interesting, in my opinion.

+5
source share
1 answer

In fact, there is an authoritative source: "The Development of the C Language" by the creator of the language, Dennis M. Ritchie :

A syntax accident contributed to the perceived complexity of the language. The indirection operator, written * in C, is syntactically a unary prefix operator , as in BCPL and B. This works well in simple expressions, but in more complex cases, brackets are required to direct the parsing. For example, to distinguish indirection from the value returned by a function from calling a function indicated by a pointer, *fp() and (*pf)() written, respectively. The style used in expressions is transferred to declarations, so names can be declared

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

In richer, but still realistic cases, things get worse:

 int *(*pfp)(); 

is a pointer to a function that returns a pointer to an integer. There are two effects. Most importantly, C has a relatively rich set of ways to describe types (compared to, say, Pascal). For example, language declarations such as C-Algol 68 describe objects that are difficult to understand, simply because the objects themselves are complex. The second effect is related to syntax details. Ads in C should be read inside out, which many people find difficult to understand [ Anderson 80 ]. Sethi [ Sethi 81 ] noted that many nested declarations and expressions would become easier if the indirection operator was taken as a postfix instead of a prefix, but by then it was too late to change.


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

B was partially based on BCPL , where the dereference operator was ! . It was on the left; binary ! was an array index operator:

a!b

is equivalent to !(a+b) .

!a

- the contents of the cell whose address is given by a; he may appear to the left of the assignment.

However, the 50-year-old BCPL manual does not even mention operators ! , instead, the operators were words: unary lv and rv . Since they were understood as if they were functions, it was natural that they preceded the operand; later, a long rv a could be replaced with syntactic sugar !a .


Using this route, you can track many of the current practices of operator C. B had a[b] equivalent to *(a + b) to *(b + a) to b[a] , as in BCPL, you can use a!b < => b!a .

Please note that the B variables are untyped, so, of course, the similarity with the declarations could not be the reason for using * on the left there.

Thus, the reason for the unary * on the left in C is just as boring as "there was no problem with simpler programs with the unary * on the left in a position in which everyone is used to having an dereference operator in other languages ​​that no one I thought that in some other way it would be better until it was too late to change it. "

+7
source

Source: https://habr.com/ru/post/1272646/


All Articles