理解对包含'++'和' - >'的表达式的评估C中的运营商

时间:2009-04-22 10:21:49

标签: c operators operator-precedence

考虑这个例子:

struct {
    int num;
} s, *ps;

s.num = 0;
ps = &s;
++ps->num;

printf("%d", s.num); /* Prints 1 */

打印1 所以我理解这是因为根据运算符优先级,->高于++,所以首先获取值ps->num(即0)然后++运算符对它进行操作,因此它将其递增为1.

struct {
    int num;
} s, *ps;

s.num = 0;
ps = &s;
ps++->num;

printf("%d", s.num); /* Prints 0 */

在这个例子中,我得到0,我不明白为什么;对于这个例子,第一个例子的解释应该是相同的。但似乎该表达式的计算方法如下:
首先,运算符++运行,并在ps上运行,因此它会将其递增到下一个struct。只有这样->才会运行,它不会执行任何操作,因为它只会获取下一个num的{​​{1}}字段,并且不执行任何操作。
但它与运算符的优先级相矛盾,运算符的优先级表示struct的优先级高于->

有人可以解释这种行为吗?

修改
在阅读了两个引用C ++优先级表的答案之后,表示前缀++ / ++运算符的优先级低于--,我做了一些谷歌搜索并提出了这个{{3表明此规则也适用于C本身。它恰好完全解释了这种行为,但我必须补充一点,这个链接中的表与我自己的K& R ANSI C副本中的表相矛盾。所以如果你有关于哪个源是正确的建议我想知道。

感谢。

8 个答案:

答案 0 :(得分:4)

后增量(ps++)和前增量(++ps)在C中具有不同的关联性。前者从左到右关联,而后者从右到左关联。检查this页面(尽管这是针对C ++的,因此优先级可能会产生误导)。

在上一个示例中,您将指针更改为&s末尾的指针。您没有更改指针的值。如果您需要增加num,则需要将++绑定到num

详细说明:

 ps++->num;

看到这个表达式的(假设的)编译器可能会将ps对象推送到堆栈,然后是++运算符,->运算符,最后是对象 - {{ 1}}。在评估时,编译器应该从哪里开始?它查看了可用的运算符,即num++。它选择->还是ps++?这里是优先规则:由于ps的优先级高于->,因此++->作为一个操作数进行处理,将num作为另一个操作数进行处理。因此,表达式的值变为ps,即0,正如您正确观察到的那样。评估后ps->num会发生什么?请记住,堆栈上还有另一个操作员?因此,编译器将此应用于ps,现在它指向一个元素超过ps

<强>脚注:

ANSI / ISO C标准不使用运算符优先级语法。相反,它使用所谓的完全因子语法。这通常涉及严格的语法定义,其中点缀有许多非终端,如“primary-expression”和“shift-expression”等。这很难理解,但对语言设计者或编译器供应商来说更容易理解。而且,这样的语法能够容易地编码优先级。但是,任何完全分解的语法都与运算符优先级语法兼容,这就是大多数书籍(和网站)所做的事情(有时还会搞乱)。

答案 1 :(得分:4)

即使++具有更高的优先级,也不会改变值 - &gt;继续运作,因为它是后增量。请参阅此代码,其中还包含此行为的另一个示例:

int b = 5;
int a = b++ * 3;
b = 5;
int c = (b++) * 3;

printf("%i, %i, %i\n", a, b, c); // Prints 15, 6, 15

struct {
  int num;
} s, *ps;

s.num = 35;
ps = &s;
printf("%p\n", ps); // Prints the pointer
printf("%i\n", ps++->num); // Prints 35
printf("%p\n", ps); // Prints the increased pointer

printf("%d\n", s.num); /* Prints 35 */

答案 2 :(得分:3)

b = ++ a;相当于:

a += 1;
b = a;

b = a ++;相当于:

b = a;
a += 1;

所以很明显为什么你没有得到你想要的结果。你描述的东西相当于(++ ps) - &gt; num。

答案 3 :(得分:1)

“precedence”基本上是派生属性;它来自解析规则。 ++ ps-&gt; num被解析为++(ps-&gt; num)/ *(),用于澄清解析规则* / 而ps ++ - &gt; num只能解析为(ps ++) - &gt; num。

答案 4 :(得分:1)

我想这是因为它们具有不同的优先级,并且在同一组中,它们具有特定的关联性(例如,评估顺序)

检查here。后缀运算符与指针解析具有相同的优先级,但前缀运算符的优先级较低。

答案 5 :(得分:1)

ps ++ - &gt; num将指针ps递增1,然后读取其中的数据。因为ps就在堆栈上的s之后,我相信指针很可能指向自己,虽然我不确定,但并不重要。基本上最初的程序是做++(ps-&gt; num)但没有括号。要实现同样的目的,但在访问数据后,您必须执行(ps-&gt; num)++,或者不使用括号:ps-&gt; num ++。

因为ps只是一个指针,即使你改变了它的值,s仍然保持不变。

答案 6 :(得分:0)

Here您可以看到++作为前缀的优先级低于 - &gt;,但作为后缀,它具有与 - &gt;相同的优先级。它从左到右进行评估,所以首先完成ps ++,然后是 - &gt;。

编辑:这是针对C ++而不是C.所以我的答案是不正确的。

答案 7 :(得分:0)

优先级用于解决模糊解析。 ++ps->num可以解析为((++ps)->num)(++(ps->num)); ++()->的相对优先级确定后者是正确的解析。

对于ps++->num,只有一个有效的解析:((ps++)->num),因此运算符的优先级无关紧要。