【问题标题】:Why pre-increment operator gives rvalue in C?为什么预增量运算符在 C 中给出右值?
【发布时间】:2011-06-15 16:43:34
【问题描述】:

在 C++ 中,预增量运算符给出左值,因为返回的是自增对象本身,而不是副本。 但在 C 中,它给出了右值。为什么?

【问题讨论】:

  • 恕我直言,这是一个很好的问题 :-)
  • @Jason : 这个问题是 C++ 特定的
  • 有许多与该主题相关的资源,包括一个涉及在 C 中不能以这种方式工作的原因的长时间讨论。
  • 我不知道一行 C++ ,但在 C 上的一切

标签: c++ c rvalue lvalue


【解决方案1】:

C 没有引用。在 C++ 中,++i 返回对 i(左值)的引用,而在 C 中,它返回一个副本(递增)。

C99 6.5.3.1/2

前缀 ++ 运算符的操作数的值递增。 结果是递增后操作数的新值。表达式 ++E 等价于 (E+=1)。

‘‘value of an expression’’ <=> rvalue

但是由于历史原因,我认为“引用不是 C 的一部分”可能是一个可能的原因。

【讨论】:

  • 但我仍然不明白为什么它会返回一个预增量的副本。为什么不返回递增的 i,就像在 i=j 中所做的那样。在这里,原始的 i 在被改变后被返回。同理,在 i=i+1 中,i 本身可以被改变后返回。
  • @HappyMittal:表达式并不真正返回值,它们具有值(或评估为值)和其他属性,例如类型和 lvalue-ness,表达式 @ 987654324@ 不“返回”副本,没有副本。 ++i 计算为 i 的新值。除非您在生成副本的更大表达式中使用它,否则没有副本。
  • @Charles Bailey:好的,我同意在 ++i 中计算出 i 的新值。但我的问题是,在 i=j 中,i 发生了变化,表达式产生了一个左值。所以 ++i 即 i=i+1 与 i=j 几乎相同,那么为什么在这种情况下,表达式不会产生左值?
  • @Happy :“好的,我同意在 ++i 中计算为 i 的新 ”并且右值表示 **value** of an expression (C99)。 i=j 也计算为一个值。尝试取(i=j)的地址,肯定会报错
  • 对不起..我不知道 i=j 也返回右值。现在明白了。
【解决方案2】:

C99 在脚注中说($6.3.2.1 部分),

“左值”这个名字最初来自 从赋值表达式 E1 = E2,其中左操作数 E1 是 必须是(可修改的)左值。 它也许被认为是更好的 表示对象“定位器” 价值''。 有时称为 “右值”在这个国际 标准描述为“价值” 一个表达式''

希望能解释为什么 C 语言中的 ++i 返回右值。


至于 C++,我想说它取决于被递增的对象。如果对象的类型是一些用户定义的类型,那么它可能总是返回左值。这意味着,如果i 的类型为Index,则您始终可以编写i++++++++++++++i,如下所述:

Undefined behavior and sequence points reloaded

【讨论】:

  • 如果对象的类型不是用户定义的类型,那么预增量必须是左值,无论如何。
  • 我在询问 C 中的行为,因为在 C++ 中,返回左值是有意义的,因为要返回递增的对象。
  • @Charles:呵呵..是的。由于OP没有提到对象的类型,我只回答了问题的一方面。
  • 请查看此评论,其中*&x 被称为表达式,并且是左值:stackoverflow.com/questions/4802315/…
  • 不幸的是,C 标准使用术语“左值”来指代表达式,以及由表达式产生的“定位器值”,并且没有将任何术语附加到过程将前者转化为后者。如果在i 为5 时执行int *p = &someAggregateArr[i++].member;,则子表达式someAggregateArr[i++].member 应该产生一个标识someAggregateArr[5].member 的“定位器值”,即使后者不是出现在代码中任何位置的表达式。跨度>
【解决方案3】:

在我的脑海中,我无法想象将预递增变量用作左值会产生任何有用的语句。在C++中,由于存在运算符重载,我可以。由于这个限制,您是否有特定示例说明您无法在 C 中执行某些操作?

【讨论】:

  • @Jason..是的。我不能在 C 中做到这一点 - int *ptr = &++i
  • @Filip 这是我(诚然不严谨)对所提出问题的回答。在 C++ 中添加重载运算符使预增量左值构造更有价值,因此添加了它。
  • +1,我认为这是一个答案,尽管不确定。在 C 中使用++i 的结果作为左值的大多数方法都是由于缺少序列点而导致的未定义行为。因此,尽管myfunc(&(++i)) 会很好并且有时很有用,但禁止它的语法并没有太大的损失。另请注意,在 C 中,(++i, i) 等同于 ++i 如果它被评估为左值,所以即使你有它的用途,它仍然不是巨大的损失。
  • 有用的语句不起作用,因为预增量不会产生左值:循环增量变量:++i %= bufsize。 (我承认,你可以用不同的方式写这个。)
  • @moooeeeep:我希望在 C 中看到一些三元复合赋值运算符,但是虽然我可以看到用于存储 x=(x+y)&z; 的运算符有很多用途,但我没有看到通过在被z 屏蔽之前存储中间值可以获得很多。
猜你喜欢
  • 2017-01-31
  • 2014-03-17
  • 2012-05-06
  • 1970-01-01
  • 2013-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多