天天看點

C語言中的自增自減運算符詳解,printf等函數的應用,及其源碼等前言

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;改變的是其自身的實參是以可以用來作為左值。

繼續閱讀