繁体   English   中英

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

[英]Understanding evaluation of expressions containing '++' and '->' operators in C

考虑这个例子:

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 只有这样->运行并且它什么都不做,因为它只是获取下一个structnum字段struct做任何事情。
但它与运算符的优先级相矛盾,后者表示->具有比++更高的优先级。

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

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

谢谢。

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

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

详细说明:

 ps++->num;

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

脚注:

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

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

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 */

b = ++ a; 相当于:

a += 1;
b = a;

b = a ++; 相当于:

b = a;
a += 1;

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

“优先权”基本上是衍生财产; 它来自解析规则。 ++ ps-> num被解析为++(ps-> num)/ *(),用于澄清解析规则* /而ps ++ - > num只能解析为(ps ++) - > num。

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

点击这里 后缀运算符与指针解析具有相同的优先级,但前缀运算符的优先级较低。

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

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

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

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

在这里您可以看到++作为前缀的优先级低于 - >,但作为后缀,它具有与 - >相同的优先级,并且从左到右进行评估,因此首先完成ps ++,然后是 - >。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM