C语言中的自增自减运算符详解,printf等函数的应用,及其源码等
- 前言
-
- 作用
- 基础的介绍
- 一些应用中的坑
-
- 连加时的加号左结合性
- 条件运算符中的短路规则
- 负号的右结合性
- printf的出栈入栈与压参打印方向
- 源码(解释一下左值的问题)
前言
本人大一新生,接触C语言才几周,所以有错的地方,还请大佬们评论区给我说一下或者私聊均可。这篇博客是我被要求做自增自减PPT的产物,原本以为很简单,逛完论坛才发现坑好多。有些不适合课上说的,都放到这了。
作用
这是最简单的了,可分为前置与后置。
前置:
#include<stdio.h>
int main()
{
int i(1);
++i;
printf("%d",i);
return 0;
}
或
#include<stdio.h>
int main()
{
int i(1);
--i;
printf(“%d”,i);
return 0;
}
后置:
#include<stdio.h>
int main()
{
int i(1);
i++;
printf(“%d”,i);
return 0;
}
或
#include<stdio.h>
int main()
{
int i(1);
i--;
printf(“%d”,i);
return 0;
}
答案就不必说了,懂的都懂,前置与后置的区别是:前置先将变量自身加一,然后再带入计算表达式;后置是先带入计算表达式,然后再将变量的值加一。
接下来以i++与++i为介绍对象,减号与之同理。
基础的介绍
1.它是单目运算符,且具有右结合性,所以只针对单个变量,无法针对表达式或常量。对于k=++i++(即k=++(i++));或6++这种类型的是错误的。
2.++i可以作为左值,但是i++不行(这个后面说源码时会介绍我自己理解的原因)
3.读取规则按照贪心法,即一个字符下尽可能多的结合其他字符。这里为了程序的可读性与后期维护,还是用括号分开吧,空格也可以起到同样的作用。
比如:对于
#include<stdio.h>
int main()
{
int a,i(1);
a=++i + ++i + ++i;
printf(“%d”,a);
return 0;
}
输出结果是a=10;i=4;(为什么a=10,后面会解释)
如果不加空格或括号的话,这个表达式会被系统依据贪心法认为是++(i++)+(i++)+i;就直接报错了。
一些应用中的坑
连加时的加号左结合性
对于刚才提到的a=++i + ++i + ++i,这两个加号的优先级一样,所以取决于其结合性。
所以系统之前读出来的不是a=(++i)+(++i)+(++i),而是a=((++i)+(++i))+(++i)。
翻译过来是这样
#include<stdio.h>
int main()
{
int i(1),a;
i=i+1;
i=i+1;
a=i+i;
i=i+1;
a=a+i;
printf(“%d”,a);
return 0;
}
所以a=(3+3)+4=10;
条件运算符中的短路规则
这个主要是if的条件中如果用了&&或||,且后面的条件包括自增自减,可能会被短路掉,不作处理。
例如:
#include<stdio.h>
int main()
{
int i(1);
if(1!=0||i++)
printf(“%d”,i);
return 0;
}
和
#include<stdio.h>
int main()
{
int i(1);
if(1==0&&i++)
printf(“%d”,i);
return 0;
}
由于都被短路掉了,所以输出的i值都是1。
负号的右结合性
由于优先级相同所以取决于“-”的右结合性,遵循从右到左的执行顺序。
这个比较简单所以不举例了。
printf的出栈入栈与压参打印方向
printf函数是先从后往前遍历所有元素并计算出每个元素对应的变量的值,然后将相应的临时变量或实参入栈,最后出栈打印。所以printf的最终打印是最后一步。i与前置最后入栈的都是i的实参,所以打印的是i的终值。而后置都是读取的相应的临时变量。
例如
#include<stdio.h>
int main()
{
int i(1);
printf(“%d %d %d %d”,i++,++i,++i,i++);
return 0;
}
对应的是4,5,5,1;
翻译一下是:
取i的值为一临时变量(q);
i=i+1;
返回i值为2;
i=i+1;
返回i值为3;
以实参i为其返回值;
i=i+1;
返回i值为4;
以实参i为其返回值;
取i的值为一临时变量(w);
i=i+1;
返回i值为5;
将“临时变量q,实参i,实参i,临时变量w”依次压入栈中,最后出栈打印。
源码(解释一下左值的问题)
int& int::operator++()
{
*this += 1;
return *this;
}
const int int::operator++(int)
{
int oldValue = *this;
++(*this);
return oldValue;
}
(来自“C语言中自增自减的编译原理”)
很明显的看到i++返回的是临时变量自然没有固定的内存地址,就做不了左值,而++i;改变的是其自身的实参所以可以用来作为左值。