3

I understand that the C standard prohibits the use of arrays as modifiable lvalues, that is, on the left-hand side of an assignment:

int lhs[4], rhs[4] = {0, 1, 2, 3};
lhs = rhs;  /* illegal! */

Now, I have been wondering why this is the case. I could see the statement above (and any other assignment that writes to an array) being defined equivalent to

memcpy((void *) lhs, (void *) rhs, sizeof(lhs));

and imposing the burden of assuring that rhs is large enough on the user, but it wasn't decided this should be the case.

However, a very similar example does work perfectly fine:

struct { int a[4]; } lhs, rhs = {{0, 1, 2, 3, 4}};
lhs = rhs;

Just by wrapping the array in a structure, we can obtain exactly the behaviour described above, that is, the assignment lhs = rhs is equivalent to:

memcpy((void *) &lhs, (void *) &rhs, sizeof(lhs));

What is the rationale for this (as I feel) inconsistency? Is there any problem with allowing array assignments interpreted as memcpys?

yyyyyyy
  • 158
  • 1
  • 2
  • 8
  • This is answered here: http://stackoverflow.com/a/17691191/14955 (Scroll down to Edit2: The Real Reason) – Thilo Jan 21 '15 at 02:13
  • An array name *is* an lvalue. I think what you're asking is why arrays aren't assignable. – Keith Thompson Jan 21 '15 at 02:24
  • Possible duplicate: http://stackoverflow.com/q/27881442/827263 – Keith Thompson Jan 21 '15 at 02:25
  • 2
    @Thilo - The "real reason" doesn't do a good job of explaining this either. For most processors, a run time pointer is not required to access an array. At compile time both the size (for early versions of C) and the relative (to the object file) location of an array is known, so arrays could have been assignable. You can define a struct with an array as it's only member, and the structure is assignable. Other languages that predate C such as APL or Cobol allow arrays to be assigned, so it's not clear to me why it was chosen to implement arrays the way its done in C / C++. – rcgldr Jan 21 '15 at 05:15
  • I feel that the "real reason" does not answer to my question. Of course, you can't "overwrite" a memory *location* (as which an array could be interpreted; this seems to somewhat agree with Ritchie's intuition), but you can write to its *contents* (as is done with structures). Besides that, it is clear that assigning to a pointer *value* is pointless (no pun intended), but *arrays are not pointers*, they just behave as if they were in certain contexts. Why couldn't you just define the left-hand side of an assignment to *not* be one of these contexts? – yyyyyyy Jan 21 '15 at 10:38

1 Answers1

1

C is supposed to be a low level language, not hiding potentially memory or time consuming tasks behind simple syntax. One operator generates one assembly instruction; for more complicated stuff call a function. In early C you couldn't assign structs either, nor pass them between functions (you'd pass a pointer).

EDIT:

A struct is one value. Its size is static and known at compile time. An array is multiple values, and most arrays are dynamically allocated/reallocated. Their size isn't known at compile time so the compiler won't know how much memory to allocate and copy.

int *a, *b;
a = malloc(/* value based on e.g. user input */);
b = a; /* compile this into what? */

For it to work, C would have to internally store an array's size together with the pointer or together with the data pointed to. This decision was left to the programmer.

GraphicsMuncher
  • 4,583
  • 4
  • 35
  • 50
potrzebie
  • 1,768
  • 1
  • 12
  • 25
  • What do you mean by "early C"? Every C *standard* I'm aware of allows assignment of structures, so your argument doesn't work for any language that can sensibly be called C. Besides that, if structure assignment was indeed added to the language later, why wasn't array assignment included as well? – yyyyyyy Jan 22 '15 at 16:41
  • About your edit: That is *not* an example of what I am talking about — your code does not even *contain* an array, plus it compiles just fine (assigning the value of the *pointer* `a` to the *pointer* `b`)! – yyyyyyy May 06 '16 at 15:30
  • @yyyyyyy potrzebie is correct: In the earliest versions of C, structs could not be assigned. See [What does impossibility to return arrays actually mean in C?](https://stackoverflow.com/questions/50808782). – Steve Summit Oct 20 '22 at 11:28
  • @potrzebie The size of a true array *is* known at compile time, so that's not the reason they can't be copied. (Actually, VLA's are an exception to that rule, but they came much later.) The thing you don't know the size of until runtime is a malloc'ed region pointed to by a pointer, but of course if you try to assign between those, you're not trying to copy the whole, unknown-size region in any case; you're merely assigning the pointer, as your example shows — and assigning pointers is perfectly fine. – Steve Summit Oct 20 '22 at 11:41