考虑这个例子:
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副本中的表相矛盾。所以如果你有关于哪个源是正确的建议我想知道。
感谢。
答案 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)
,因此运算符的优先级无关紧要。