2

考虑这个例子:

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。只有 then->操作并且它什么都不做,因为它只是获取num下一个字段struct并且什么都不做。
但这与运算符的优先级相矛盾,运算符的->优先级高于++.

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

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

谢谢。

4

8 回答 8

4

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

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

详细解释:

 ps++->num;

一个(假设的)编译器在看到这个表达式时,可能会将ps对象推入堆栈,然后是++运算符、->运算符,最后是对象 -- num。在评估时,编译器应该从哪里开始?它着眼于可用的运算符 ie++->. 它选择ps++还是ps?这里的优先级规则:由于->具有比 更高的优先级++,因此需要->将 withnum作为一个操作数和ps另一个操作数进行处理。因此,正如您正确观察到的那样,表达式的值变为ps->num0。ps评估后会发生什么?还记得,堆栈上还剩下另一个运算符吗?因此,编译器将此应用于ps现在它指向过去的一个元素&s

脚注:

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

于 2009-04-22T10:29:28.330 回答
4

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

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 */
于 2009-04-22T10:30:41.883 回答
3

b = ++a; 相当于:

a += 1;
b = a;

b = a++; 相当于:

b = a;
a += 1;

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

于 2009-04-22T10:39:51.487 回答
1

“优先级”基本上是一个派生属性;它遵循解析规则。++ps->num 被解析为 ++(ps->num) /* () 为澄清解析规则而添加 */ 而 ps++->num 只能被解析为 (ps++)->num。

于 2009-04-22T10:31:45.097 回答
1

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

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

于 2009-04-22T10:31:52.630 回答
1

ps++->num 将指针 ps 加 1,然后读取其中的数据。由于 ps 就在堆栈上的 s 之后,我相信指针很可能会指向它自己,尽管我不确定,也不重要。基本上最初的程序是在做 ++(ps->num) 但没有括号。要实现相同的目的,但在访问数据之后,您必须执行 (ps->num)++,或者不使用括号:ps->num++。

而且由于 ps 只是一个指针,即使您更改了它的值, s 仍然保持不变。

于 2009-04-22T10:35:57.177 回答
0

在这里可以看到++作为前缀的优先级低于->,但是作为后缀它的优先级与->相同,并且是从左到右求值的,所以先做ps++再做->。

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

于 2009-04-22T10:29:23.557 回答
0

Precedence is used to resolve ambiguous parsing. ++ps->num could be parsed as ((++ps)->num) or (++(ps->num)); the relative precedence of ++() and -> determines that the latter is the correct parsing.

For ps++->num, there is only one valid parsing: ((ps++)->num), so the precedence of the operators doesn't matter.

于 2010-03-01T20:06:28.873 回答