以C++编译通过但C编译会报错(错误:需要左值作为一元'&'操作数)

5

当我使用C++编译时,这一行代码可以通过编译,但是在C中不行:

gmtime(&(*(time_t *)alloca(sizeof(time_t)) = time(NULL))); //使用alloca创建一个左值

我对这种差异感到惊讶。甚至在C++中也没有警告。

当我指定gcc -x c时,会出现以下消息:

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

这里的 & 不仅是一个取地址符,为什么在 C 和 C++ 中会有所不同?

虽然我可以在 C 中使用复合字面量,但是否有可能修改我的语法使其在 C 和 C++ 中都能工作?


2
此外,差异不在于 &,似乎在于 (*(time_t *)alloca(sizeof(time_t)) = time(NULL)) 是否为左值。 - user253751
1
另外,为什么不把它写成两行呢?time_t t = time(NULL); gmtime(&t); - user253751
@immibis主要是因为我想获取临时对象的地址(time_t值仅被使用一次)。我发现C语言中的复合字面量非常方便,但是在C++中我无法使用它。 - cshu
1个回答

8
在C11 6.5.16/3中:
赋值运算符将一个值存储在左操作数所指定的对象中。赋值表达式在赋值后具有左操作数的值,但不是lvalue
在C++14 5.17/1中:
赋值运算符(=)和复合赋值运算符都是从右到左组合的。所有运算符都需要可修改的lvalue作为左操作数,并返回引用左操作数的lvalue
(每种语言标准的早期版本都指定了同样的内容)。
由于取地址运算符只能对lvalue进行操作,因此该代码在C++中是正确的,但在C中不正确。
关于问题“是否可以修改我的语法使其在C和C ++中都能工作?”。这不是一个理想的目标;这两种语言是不同的,你应该决定你要写什么。这就像试图坚持适用于C和Java的语法一样没有多大意义。
正如其他人建议的那样,您可以编写:
time_t t = time(NULL);
gmtime(&t);

以下是相比您原来的代码更有优势的部分:

  • 更简单,因此更易于理解和维护
  • 不依赖于非标准的alloca函数
  • 没有潜在的对齐问题
  • 使用的内存不多,甚至可能更少

我不知道这个规则背后的理由,但我猜最初在 C 语言中它从来不是一个左值(很少有原因去尝试修改赋值的结果),但当 C++ 开发时,他们将其改为左值以保持与重载 operator= 并返回自身引用(即左值)的对象一致性。 - M.M
干得好。我知道这与rvalues和lvalues的不同规则有关,但我一直在研究&运算符而不是=运算符。+1。 - ApproachingDarknessFish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接