C语言常见问题——++i与i++详解

本文探讨了C语言中自增运算符(++i与i++)的使用及其在不同编译环境下的表现,包括它们在表达式和函数调用中的行为差异。

目录

一、++i与i++

1.引例

2.(i++)+(i++)+(i++)与(++i)+(++i)+(++i)

3.总结

二、函数中的++

1.printf中的++

2.++作为函数的参数 

3.总结


一、++i与i++

1.引例

对于如下程序,其输出结果是什么

#include <stdio.h>
int main()
{
    int i=1,a=0,b=0;
    a=i++;
    b=++i;
    printf("i=%d,a=%d,b=%d\n",i,a,b);
    return 0;
}

解析:

a=i++;等价于a=i;i=i+1;

b=++i等价于i=i+1;b=i;

通俗地讲,i++是先赋值再自增,++i是先自增再赋值

2.(i++)+(i++)+(i++)与(++i)+(++i)+(++i)

那么,如果一条语句中有多个i++/++i呢?例如: 

#include <stdio.h>
int main()
{
    int i=2,j=2,a=0,b=0;
    a=(i++)+(i++)+(i++);
    b=(++j)+(++j)+(++j);
    printf("i=%d,j=%d,a=%d,b=%d\n",i,j,a,b);
    return 0;
}

        首先明确一点,多个++之间的和运算没有统一的定义,也就是说在不同编译环境下其结果有可能不同。

在codeblocks编译器下(gcc/g++):

解析:

我们可以从结果来猜测运算的情况:

a=(i++)+(i++)+(i++)=2+3+4=9

b=(++j)+(++j)+(++j)=4+4+5=13

1)初始化时:i <- 2,j <- 2

2)对于多个表达式相加的情况,gcc是从左往右累加的,并且是两个表达式两个表达式地加

3)在执行a=(i++)+(i++)+(i++)时,会以(i++)为单位把i的值传送回来再自增,运算过程就是(2+3)+4=5+4=9;a <- 9;

4)执行b=(++j)+(++j)+(++j)时,

遇到第一个(++j),j先自增一次(j=3);在遇到“+”时,不会先把j的值传送回来,而是先计算加法运算的第二个操作数,于是遇到第二个(++j),j自增一次(j=4),此时j的值(4)才传送回来进行加法运算,这时右边的表达式相当于(4+4)+(++j)=8+(++j);接着遇到第二个“+”,就先进行第三个(++j)的运算,j再自增一次(j=5),传送回j的值(5)之后才进行加法运算,即8+5=13;a <- 13;

vs编译器下:

解析:

我们可以从结果来猜测运算的情况:

a=(i++)+(i++)+(i++)=2+2+2=6

b=(++j)+(++j)+(++j)=4+4+5=13

1)初始化时:i <- 2,j <- 2

2)在执行a=(i++)+(i++)+(i++)时,vs会以整个赋值语句为单位,先用i的初始值进行运算,待赋值语句结束后,才对i进行三次自增,即2+2+2=6;a<-6 ;i=i+1;i=i+1;i=i+1;

3)执行b=(++j)+(++j)+(++j)时,vs与gcc相同,在遇到“+”时,不会先把j的值传送回来,而是先对加法的第二个操作数进行运算,待参与加法的第二个操作数运算完成后才传送回j的值,运算过程为(4+4)+5=13;b <- 13;

在TC编译器下:

如果有多个表达式参与和运算,则先计算各个表达式,再进行加运算

如果i和j的初始值都为2,则

a=(i++)+(i++)+(i++)=2+2+2=6,

b=(++j)+(++j)+(++j)=5+5+5=15

        a(b)在不同编译器中运算的结果不同,主要是因为变量i(j)传值回来的时间不同,以及多个表达式进行和运算时执行的方式不同(例如gcc和vs执行多表达式的和预算时,只能先计算左边两个表达式的和,等计算出和以后再计算该和与第三个表达式的和,以此类推;而TC可以同时进行多个表达式的加法运算)。

        此外注意:在C程序的实际执行过程中,并不是直接一条一条高级语言地执行,我们会先对C代码进行预编译,然后编译成汇编代码,汇编代码经汇编生成二进制代码,二进制代码经链接生成可执行文件,最后我们才运行这个可执行文件。所以本质上a(b)在不同编译器中运算的结果不同,是因为对应语句生成的汇编代码不同。

3.总结

        我们不推荐类似(i++)+(i++)+(i++)多个自增表达式相加的写法。因为这类写法的实现没有统一的定义,在不同的编译环境下可能有不同的结果。


二、函数中的++

1.printf中的++

#include <stdio.h>
int main()
{
    int i=0,a=0,b=0;
    i=1;
    printf("a=%d,i=%d\n",a=i++,i);
    i=1;
    printf("b=%d,i=%d\n",b=++i,i);
    return 0;
}

codeblocks:

vs:

可以看到printf中的++也是一个不明确的行为 

2.++作为函数的参数 

#include <stdio.h>
void f(int i1,int i2,int * pi){
    printf("f(%d,%d)在函数体中,i在内存中存储的值为%d\n",i1,i2,*pi);
    return;
}
int main()
{
    int i=0;
	f(i++,i++,&i);
	i=0;
	f(++i,++i,&i);
    return 0;
}

 codeblocks:

vs:

可以看到,i++作为参数传递时也是一个不明确的行为

3.总结

        在调用printf或者其他函数时,我们要避免在函数的参数表达式中使用自增运算符++。尽量在函数调用语句的前一条语句或后一条语句完成对变量值的修改,同时也可以考虑使用i=i+1替代++i作为参数。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

易水卷长空

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值