C中的指针操作和运算符优先级

Posted

技术标签:

【中文标题】C中的指针操作和运算符优先级【英文标题】:Pointer operations and operator precedence in C 【发布时间】:2014-01-24 06:33:20 【问题描述】:

背景

今天刚和一个 C 家伙聊天,我们在以下问题上存在分歧:

int intgA[2] =  1, 2 ;
int intgB[2] =  3, 5 ;

int *intAPtr = intgA;
int *intBPtr = intgB;

所以当我们这样做时:

*intAPtr++ = *intBPtr++;

我的分析

第一:

intBPtr 加一,现在指向地址 5。 然后,顺从,保持值5;

intAPtr 也加一,现在指向地址 2。 后续引用,值为2;

最后:

2 被 5 替换。

所以它们分别是:5 和 5。

他的分析

*intBPtr 的值首先赋值给*intAPtr

因此,它们变成:3 和 3。

然后*intAPtr*intBPtr 都加一。

因此,它们分别变为:4 和 4。

我的假设

我认为++ 运算符优先于*=,因此是我的断言。

例如,如果我们有:

*intAPtr++; 

结果应该是 2,对吧?因为我们先增加指针,然后取消引用。

那么为什么在上述情况下,正如他所说,我们首先将 intBPtr 的值分配给 intAPtr 的值,然后再递增这些值?

在接受了这里的所有建议后,我在 IDE 中运行了代码,结果证实了@sujin:

虽然它证实了我至少在优先级方面是正确的:

那个:*intAPtr++ = *intBPtr++;

intAPtr++ 具有更高的优先级,这导致:intAPtr 将其地址增加 1。

现在指向:2的地址。

同样:

intBPtr++ 也加 1(地址)。

现在指向:5的地址。

那就轮到*了:

因此两者都被取消引用 (*) 分别为 2 和 5。

但是问题仍然存在,因为上面的分配 (=) 似乎没有发生。

如果是这样,两者都会变成 5。

期待进一步开悟。

【问题讨论】:

intAPtr++ 是一个后增量。增量操作很可能发生在分配之后最后。您是否尝试过将此代码放入 IDE 并运行它,看看它做了什么? 指针的增量何时发生与赋值无关。后增量的返回值是一个新的临时对象,与正在递增的指针分开。 @Cubbi:只需运行代码就可以验证行为需要 5 分钟。 【参考方案1】:

声明

*intAPtr++ = *intBPtr++;

被解析为

*(intAPtr++) = *(intBPtr++);

分解如下:

intBPtr(3)当前指向的值赋值给intAPtr(intgA[0])指向的位置; 指针 intAPtrintBPtr 递增。

这些事情发生的确切顺序是未指定;您不能依赖 intBPtrintAPtr 之后递增,反之亦然,也不能依赖在递增之前发生的赋值等。

所以当这一切都完成时,intgA[0] == 3intAPtr == &intgA[1]intBPtr == &intgB[1]

表达式a++ 计算为a 的值之前 增量。

【讨论】:

The exact order in which these things happen is unspecified+1。【参考方案2】:

你和对方都错了!

要么, 1. 两个指针都先递增,然后赋值或 2. 一个指针递增,然后赋值发生,然后另一个指针递增或 3. 第一次赋值发生,然后指针递增。

但规则是,一个语句的所有副作用必须在下一个语句开始之前完成。请记住,必须使用原始值。只要使用原始值,随时都可以递增。

C-faq: 3.2:

不保证在放弃前一个值之后以及在计算表达式的任何其他部分之前立即执行递增或递减。 仅保证更新将在表达式被视为“完成”之前的某个时间执行

阅读Eric Lippert给出的answer了解详细说明。

【讨论】:

感谢您的支持。我注意到你在第二个陈述中留下了一个案例。 “...或者一个指针递增,然后赋值发生,然后另一个指针递增”。 @EricLippert;感谢您指出。在答案中添加了这种情况。 :)【参考方案3】:

是的,++ 的绑定比 * 更紧密,但您误解了它的工作原理。 var++ 增加 var,但它计算为 var 的值之前增量。如果您愿意,可以将其视为(var += 1, var - 1) 的语法糖。

另一种思考方式是:如果它按照您认为的方式工作,那么var++++var 之间将没有区别,其中一个不会包含在第一名。 C 几乎没有冗余。

(绑定优先级确实很重要;例如,这意味着*var++ 增加变量var 的值,而(*var)++ 增加内存位置*var 中的值。 )

【讨论】:

这位同事也不正确,因为 ++ 与指针有关,而不是与值有关,正如他似乎声称的那样...... @glglgl Doh,我误读了这个问题。我想我会删除该声明而不是尝试更详细地解释。 @hacks No. var 不一定是内存位置(它只能存在于寄存器中),但*var 绝对是内存位置。不过,我发现我写的内容可能会更清晰。 var 被声明为指针。我认为在 *var++ 的情况下,var++ 首先发生(优先级),这会增加内存位置,然后发生 *,这会将其取消引用到它的值。如果var 被声明为变量,var++ 当然意味着增加var 的值,正如您所声称的,这里不是这种情况,因为var 被声明为指针。 @Unheilig 不,你坚持你最初的误解。 ++*var++ increments var(而不是内存位置*var)中的++ 因为优先,但它计算为 var 的值在增量发生之前,这意味着整个表达式的值是var 最初指向的内存位置中的值。再看看我写的关于语法糖的文章。【参考方案4】:

++ 运算符的主要作用是产生其操作数的值(没有增加它)。副作用是增加操作数。

即使在主效果产生的值用于另一个操作之前执行了副作用,主效果产生的值是操作数的原始值,而不是更新后的值。

*x++(解析为*(x++))中,* 运算符应用于主效果产生的值,因此* 操作与评估*x 相同。增量发生在“侧面”,在主表达式评估之外,因此它不参与确定*x++ 的值。

【讨论】:

【参考方案5】:

示例代码(在 linux 中):

#include <stdio.h>
#include <stdlib.h>
int main() 
    int intgA[2] =  1, 2 ;
    int intgB[2] =  3, 5 ;
    int *intAPtr = intgA; //1
    int *intBPtr = intgB; //3
    *intAPtr++ = *intBPtr++;
    // *intAPtr = *intBPtr;
    // *intAPtr++ = 25; 
    printf("op: %d %d\n", *intAPtr, *intBPtr);

   return 0;

输出:

op: 2 5

首先将intBPtr 分配给intAPtr 然后发生增量,因为它是后增量。

【讨论】:

首先将 intBPtr 分配给 intAPtr,然后发生增量。:你怎么能这么说?【参考方案6】:

我同意 John Bode 的回答,以简化一点 我就直接写代码吧:

   *intAptr = * intBPtr;

等于:

   *intAptr =*intBPtr 
   intAPtr+=1;
   inrBPtr+=1;

所以我们得到的是: intAPtr 指向 2 intBPtr 指向 5

【讨论】:

以上是关于C中的指针操作和运算符优先级的主要内容,如果未能解决你的问题,请参考以下文章

c语言中规定 赋值运算符的左边必须是啥?

C语言 符号优先级的排列顺序

深入了解C指针

求一份儿C语言优先级调度算法要求如下

《C指针全解》让你不再害怕指针

让你不再害怕指针——C指针详解(经典,非常详细)