5

This line compiles when I use C++, but not C:

gmtime(&(*(time_t *)alloca(sizeof(time_t)) = time(NULL))); //make an lvalue with alloca

I'm surprised by this difference. There is not even a warning for C++.

When I specify gcc -x c, the message is:

playground.cpp:25:8: error: lvalue required as unary '&' operand
 gmtime(&(*(time_t *)alloca(sizeof(time_t)) = time(NULL)));
        ^

Isn't the & here just an address-of operator? Why is it different in C and C++?

Although I can use compound literals in C, still is it possible to modify my syntax to make it work in both C & C++?

cshu
  • 5,654
  • 28
  • 44
  • 2
    Also the difference isn't about `&`, it seems to be about whether `(*(time_t *)alloca(sizeof(time_t)) = time(NULL))` is an lvalue or not. – user253751 Dec 30 '15 at 06:15
  • 1
    Also, why not just write this on two lines? `time_t t = time(NULL); gmtime(&t);` – user253751 Dec 30 '15 at 06:16
  • @immibis mainly because I want to get an address of a temporary object (the `time_t` value is used only once). I found compound literals in C so convenient but I cannot use it in C++. – cshu Dec 30 '15 at 06:21

1 Answers1

8

In C11 6.5.16/3:

An assignment operator stores a value in the object designated by the left operand. An assignment expression has the value of the left operand after the assignment, but is not an lvalue.

In C++14 5.17/1:

The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand and return an lvalue referring to the left operand.

(Earlier versions of the language standards in each case specified the same thing).

Since the address-of operator can only operate on an lvalue, the code is correct in C++ but not in C.


Regarding the question "Is it possible to modify my syntax to make it work in both C & C++?". This is not a desirable goal; the two languages are different and you should decide what you're writing. This makes about as much sense as trying to stick to syntax that works in both C and Java.

As suggested by others, you could write:

time_t t = time(NULL);
gmtime(&t);

which has the benefits over your original code of being:

  • simpler, therefore easier to understand and maintain
  • does not depend on non-standard alloca function
  • does not have potential alignment violation
  • uses no more memory and perhaps uses less
M.M
  • 138,810
  • 21
  • 208
  • 365
  • I don't know the rationale behind the rule, but I'd figure that originally in C it was never an lvalue (there's rarely any cause to try and modify the result of an assignment), but when C++ was being developed, they changed it to be an lvalue for consistency with objects that overload `operator=` and return a reference to self (which is an lvalue). – M.M Dec 30 '15 at 06:27
  • Nice job. I knew it had to do with different rules concerning rvalues and lvalues but I was looking into the `&` operator and not the `=` operator. +1. – ApproachingDarknessFish Dec 30 '15 at 06:27