*p++在解引用后会自增吗?

26

我不太确定这里的顺序是什么。是: 1)在增加指针p的值后取消引用它 2)在取消引用指针p的值之前增加它

5个回答

41

在递增和解引用操作之间没有顺序关系。但是,* 运算符应用于 p++ 的结果,即递增之前 p 的原始值。


2
后增量和后减量运算符将其操作数的值增加(或减少)1,但表达式的值是在增量(或减量)操作之前操作数的原始值。 - blasrodri

15

运算符表格中,你可以看到后缀运算符++比一元运算符*的优先级高。

因此,*p++会增加p(而不是*p),并返回p在递增之前包含的地址的值(因为它是后缀 ++)。

但是这个顺序与实现相关。它可能首先解引用p,然后递增它,也可能存储p的旧值,递增它,然后解引用旧值。


5

试一下。这个程序

#include <stdio.h>

int main(void) {
    int p[2];
    int *q = p;
    p[0] = 10;
    p[1] = 100;

    printf("%d\n", *q++);
    printf("%d\n", *q);

    return 0;
}

打印
10
100

展示了++应用于p,而不是*p,并且递增发生在解除引用之后。编辑:(感谢@EricLippert说服我撤下K&R)不仅可能存在happens-after关系,而且根据K&R第203页的说法,必须存在:

后缀表达式后跟++或--运算符是后缀表达式。 表达式的值是操作数的值。 在注意到值之后,将增加(++)或减少(--)操作数1。

(强调我的)。当然,我不认为K&R在存在多线程的情况下对C的语义有任何说明(根据维基百科,pthreads规范是在1995年发布的),但对于单线程程序,K&R非常清楚。

4
稍等一下。在 C 语言中肯定存在“happens after”关系;无论是否存在,都是编译器实现的细节。C 编译器有很大的自由度来选择如何在序列点内对副作用进行排序,如果它希望,则可以选择在所有其他内容之后执行 ++ 的副作用。C# 编译器没有同样的余地;C# 规范非常清楚地规定了必须何时观察到该副作用。(在一个执行线程内观察到;另一个线程观察到副作用的顺序是未指定的。) - Eric Lippert

4

给定 q = *p++;,q 会得到指针 p 自增之前所指向的值。另一种说法是,表达式 *p++ 的值是指针 p 自增之前所指向的值。


它可能会找到 *p,增加 p 并将先计算出的 *p 的值赋给 q - asaelr
@asaelr 这是一个公正的观点,即赋值可能在增量之后发生,但效果是相同的:在p被递增之前,q获取了*p的值。 - Caleb
效果是一样的,但问题是先发生什么。 - asaelr
这个问题与赋值无关--OP想知道增量或解引用哪个先发生。无论如何,重写了答案以考虑您的关注。 - Caleb
好的,差异也可能在增量之后。 - asaelr
@asaelr 抱歉——不确定为什么我的第一次编辑没有完全生效。我试图让它尽可能清晰明了。 - Caleb

4
后缀运算符++--的优先级高于前缀一元运算符。因此,*p++等同于*(p++);它会递增p,并返回p在递增之前所指向的值。
要递增p所指向的值,请使用(*p)++(如果副作用的评估顺序不重要,则可以使用++*p)。

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