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

1 Answer 1

9

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.

Sign up to request clarification or add additional context in comments.

9 Comments

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?
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: Thanks. I never quite got my head around the rules for temporary objects.
@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.
@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.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.