7

I have a matrix struct:

typedef struct Matrix
{
    float m[16];
} Matrix;

When I try to call this function:

memcpy(m->m, MultiplyMatrices(m, &translation).m, sizeof(m->m));

I get an error at compile time saying:

error: invalid use of non-lvalue array

MultiplyMatrices returns a Matrix.

I only get this error if I use gcc to compile the file into an object, if I use g++ to compile the object I get no error.

I am not even sure what the error means, I have a feeling it has to do with the array stored in the Matrix returned by MultiplyMatrices.

If you need to see more code let me know.

This code is from this tutorial: OpenGL Book Chapter 4

p.s. I would like to keep this code strict iso/ansi, if there is no other solution however, then I'll just have to deal with it.

EDIT: I ended up going with creating a temporary Matrix then copying the array.

Matrix tempMatrix;

...

tempMatrix = MultiplyMatrices(m, &translation);
memcpy(m->m, tempMatrix.m, sizeof(m->m));
miningold
  • 699
  • 2
  • 9
  • 19

1 Answers1

8

The return value of MultiplyMatrices() is not an lvalue (like the return value of any function), which means that you can't take its address. Evaluating an array (including an array member of a structure) implicitly takes the address of the first element, so you can't do that.

You can, however, use simple assignment of the containing struct:

*m = MultiplyMatrices(m, &translation);

As long as your struct only contains the one element as you have shown, this is exactly the same.

caf
  • 216,678
  • 34
  • 284
  • 434
  • `memcpy(m->m, &MultiplyMatrices(m, &translation).m[0], sizeof(m->m));` makes the error go away, for me at least (GCC 4.5.2). So the return value of a function is not an lvalue, so I cannot take a pointer to it, but I can take a pointer to its first element? Or GCC has a bug? – Nemo Jul 11 '11 at 04:08
  • 1
    At that point you've dereferenced the first element in the array, which *is* an lvalue ... you can then properly take the address of that element. Basically you can't apply the address-of operator to a rvalue, but you can apply it to an lvalue. The implicit conversion of an array to a pointer to that array occurs because arrays are lvalues. If you return an rvalue from a function (which is what always happens), that implicit conversion can't take place since rvalues have no memory address (they are temporary values contained in the CPU's registers, not memory). – Jason Jul 11 '11 at 04:10
  • @Jason: Thanks. I never quite got my head around the rules for temporary objects. – Nemo Jul 11 '11 at 04:13
  • @caf It would actually have to be `*m = MultiplyMatrices(m, &translation);` I forgot to mention that m is a `Matrix*`. It seems like it will work I'll have to try it out. Thank you. – miningold Jul 11 '11 at 04:18
  • @Nemo I got this warning when using your suggestion: `warning: ISO C90 forbids subscripting non-lvalue array` – miningold Jul 11 '11 at 04:23
  • BTW, I was thinking about `memcpy(m->m, &MultiplyMatrices(m, &translation).m[0], sizeof(m->m));` a little more ... doing that will give you the address of memory somewhere on the stack ... and it's temporary memory since the `MultiplyMatricies` function returns a temporary `Matrix` object which has been allocated on the stack. So this will probably cause some other issue further down the line depending on how `memcpy` decides to use the stack (i.e., those temporary values in the array could be erased). – Jason Jul 11 '11 at 04:28
  • 1
    @Jason: It is in fact undefined behaviour to access a function return value after the next sequence point, and there's a sequence point here before `memcpy()` is called. – caf Jul 11 '11 at 04:42
  • [Keith Thompson](http://stackoverflow.com/a/8775291/318716) seems to say `memcpy(m->m, &MultiplyMatrices(m, &translation).m[0], sizeof(m->m))` is well defined in _C11_. Is this correct? – Joseph Quinsey Feb 17 '14 at 16:10
  • 1
    @JosephQuinsey: Yes, that appears to be the case. The return value is now valid until the end of the *full expression*, not just the next sequence point. – caf Feb 18 '14 at 02:20