在C语言中,i++和(i)++有什么区别?

51
int i = 3;
int j = (i)++;
vs
int i = 3;
int j = i ++;

上述两种情况的评估方式有区别吗?

第一种情况是否等同于对rvalue进行递增,还是未定义行为?


18
宏定义中似乎随意使用圆括号很常见。在真正起到作用的地方,你希望得到错误提示信息,不过通常情况下是这样的。 - Hans Passant
3
对于整数类型而言,括号和运算符没有区别。然而,并非总是如此,在组合括号和运算符时需要谨慎,@govin-parmar给出了一个很好的例子,展示了指针可能发生的情况。 - Tomasz Kornuta
1
要明确的是,这两种情况都是明确定义的(即不是未定义行为),并且将在j中存储3。 - osuka_
1
"我是不是想太多了" 是的。 - alk
2个回答

97

i++(i)++的行为是相同的。C 2018 6.5.1 5表示:

带括号的表达式是基本表达式。它的类型和值与不带括号的表达式相同。如果不带括号的表达式是一个左值、函数指示器或空表达式,则它是一个左值、函数指示器或空表达式。

在C 1999中,措辞是相同的。


2
为了完整性,这一直是这样吗?我的意思是,我知道它是这样的,但你的参考资料说C 2018(即最新版本),所以将其详细说明也无妨。 - Mr Lister
7
是的,即使在 ANSI C 标准(1978 年)之前也有这种行为。虽然没有正式明确规定(当时很少有),但在 K&R 的第一版中的一些示例中需要这样做,比如 (*ptr)++ - Sneftel

56
在你提到 i++(i)++ 的简单示例中,如Eric Postpischil的答案所述,它们之间没有区别。但是,如果你使用*运算符解引用一个指针变量并使用增量运算符,则这种差异实际上是有意义的;*p++(*p)++ 之间存在差异。
前者语句对指针进行了解引用操作,然后增加了指针本身; 后者语句解引用指针,然后增加了被解引用的值。

7
例如,如果您定义了一个宏 #define postinc(x) x++,那么使用函数式的方式 postinc(*p) 将不会按照您的期望进行操作。这就是为什么在编写宏时通常会使用大量括号进行加强措施,例如 #define postinc(x) ((x)++) - Daniel Schepler
12
你的回答可以归结为“括号可以用来强制运算符优先级”,这是显而易见的,不是OP所问的内容。 - Giacomo Alzetta
3
这个答案引发了一次长时间的讨论,但被调解员删除了。简单来说,我认为解释这个细微差别很重要,因为在C语言初学者中混淆这两个表达式是常见的bug来源。 - Govind Parmar
7
请记住,Stack Overflow 的答案应该对所有阅读问题的人都有用,而不仅仅是提问者或熟悉所询问技术的人。根据我的经验,(expr) ++ 最常见的用法是对解除引用的值进行递增操作,因此让初学者产生 expr ++ 与其等价的印象是有害的。 - Govind Parmar
3
不,第一个会先取消指针引用,然后再将其递增。第二个会先将指针递增,然后再取消引用它。 - ale10ander
显示剩余6条评论

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