10

From C11 standard (§6.3.2.1 Lvalues, arrays, and function designators):

A modifiable lvalue is an lvalue that does not have array type, does not have an incomplete type, does not have a const-qualified type, and if it is a structure or union, does not have any member (including, recursively, any member or element of all contained aggregates or unions) with a const-qualified type.

From C in a Nutshell:

A modifiable lvalue is an lvalue that is not declared as a const -qualified “Type Qualifiers” on page 180), and that does not have an array type.

What is the reason that a modifiable lvalue can't have an array type?

Is an object of an array type always implicitly const?

phuclv
  • 37,963
  • 15
  • 156
  • 475
Tim
  • 1
  • 141
  • 372
  • 590
  • 3
    You can assign to modifiable lvalues; you can't assign to arrays (only to elements of arrays), so an array name can't be a modifiable lvalue. – Jonathan Leffler Aug 13 '17 at 00:53
  • Thanks. Does a function name have similar behavior to an array name? But a function name is not a lvalue or nonlvalue. lvalue and nonlvalue can only be an object expression. – Tim Aug 13 '17 at 00:55
  • In some respects, a function name is like an array name; you certainly can't assign to a function name — but you can use it to call a function or to initialize a function pointer. The point of the name 'modifiable lvalue' is that you can use `lvalue = rvalue;` in an assignment. – Jonathan Leffler Aug 13 '17 at 00:58
  • An array name is an unmodifiable lvalue. Then is a function name an unmodifiable what? – Tim Aug 13 '17 at 01:04
  • 1
    It's a non-modifiable lvalue. The standard mentions 'rvalue' once, in footnote 64 to §6.3.2.1: _What is sometimes called ‘‘rvalue’’ is in this International Standard described as the ‘‘value of an expression’’._ It also specifies (a couple of sentences before your quote) a general lvalue as: _An lvalue is an expression (with an object type other than void) that potentially designates an object;(64) if an lvalue does not designate an object when it is evaluated, the behavior is undefined._ Footnote 64 also says an lvalue could be: _…considered as representing an object ‘‘locator value’’._ – Jonathan Leffler Aug 13 '17 at 01:10
  • Thanks. "An lvalue is an expression that designates an object." from C in a Nutshell, and a function name designates a function not an object, so a function name can't be an lvalue, so can't be a nonmodifiable lvalue. – Tim Aug 13 '17 at 01:15
  • Yes, that's another way of looking at it — functions ain't objects (and pointers to functions ain't pointers to objects, and pointers to functions ain't required to be convertible to a pointer to object, and …). There are reasons for using comments — they don't get down-voted like answers do when you make minor thinkos in them. – Jonathan Leffler Aug 13 '17 at 01:17
  • 1
    There's no hugely profound reason; it's simply a choice made by the language designers. Quite possibly it's because assigning arrays could have arbitrarily high cost, and they didn't want that cost to accrue "silently". But that's speculation. You can trivially assign arrays by making them members of a struct and then assigning *those* lvalues. – Kerrek SB Aug 13 '17 at 01:31
  • @KerrekSB You're right about this being a language designers' choice, but your guess about performance is not. A `struct` can contain an array, and structs are assignable. – Gene Aug 13 '17 at 21:38
  • @Gene: Yes, didn't I just say as much in the last sentence? Anyway, I think C tries to make a somewhat strong distinction between fundamental types and user-defined types (e.g. you have to spell `struct` in front of UDTs), so it stands to reason that `struct` serves as a universal warning that it "may be expensive to use", so having an array inside the struct isn't considered quite as subtle. – Kerrek SB Aug 14 '17 at 00:35
  • @KerrekSB Thanks. What do you mean by "You can trivially assign arrays by making them members of a struct and then assigning those lvalues"? I define a struct type with a member being an array `typedef struct { int arr[3];} MyType;` Then `MyType myStruct;` and `myStruct.arr = (int[]) {3,2,1};` and got `error: assignment to expression with array type`. – Tim Aug 14 '17 at 19:00
  • @KerrekSB https://stackoverflow.com/q/45681431/156458 – Tim Aug 14 '17 at 19:12

1 Answers1

10

The designers of the C language decided that it should not be possible to assign arrays by value. At the time this seemed a sensible decision (early 1970s) - memory and processor speed were very limited and they considered that having a = b; make a and b both refer to the same array was something that would be a much more common intent than having a = b; be used to copy the contents of one array to another.

In fact this was already common usage: in the B programming language (precursor to C), the equivalent of int a[10]; actually meant to allocate both a pointer, and a block of 10 ints, and point the pointer to the block of 10 ints. You could actually make an array "point" somewhere else in B.

C changed the meaning of an array definition that it only allocates the block of ints; and added "The Rule": when you use the array's name in an assignment expression (and most other expressions) the array is implicitly converted to a pointer to the first element. So, if a is a pointer and b is an array, then you can still write a = b; to make a behave like an alias for b. Although you can no longer have a = b; where a is an array.

In the first ANSI C standard in 1989 they added the ability to copy structs by value (this had existed in some compilers previously but wasn't universal), with the corollary that if the struct contains an array then the array gets copied by value. But it was far too late to go back and change the meaning of a = b; to copy arrays by value, too much code was written that already depends on The Rule.

Reference: The Development of the C Language - Dennis M. Ritchie

M.M
  • 138,810
  • 21
  • 208
  • 365