C語言中副作用和序列點(關於自增自減)

自增自減運算符很常見,先後關係大家一定都知道,但是在某些情況下可能會變的有些複雜,這對於初學者造成很大困擾,《C primer plus》一書中“副作用和序列點”這一節比較清晰的說明了特殊情況的運算順序。

副作用:

C語言中副作用就是對數據對象或文件的修改。從C語言的角度上來看,它的主要目的是對錶達式求值,至於賦值,修改這些對於我們來說的主要目的在C語言來看都是副作用。

例如,

調用printf函數,它的主要目的就是返回值。而在控制檯顯示是他的副作用。

對於a = 1;這條語句,它的主要目的也就是對該表達式求值,求出是1。至於將1賦值給a則是副作用。

我的看法是將語句和自定義的函數類比,函數體內我們實現各種功能,最後返回一個值,這個返回的值就是主要目的,其餘的實現的功能就是副作用。(這句純粹自己的理解)

序列點:

序列點是程序執行的點,在該點上所有的副作用都要在進入下一步之前完成。

C語言中,語句的分號標記了一個序列點。任何一個完整的表達式的結束也是一個序列點。還有一些運算符也有序列點。

推薦一篇博客《C語言中的序列點》

什麼是完整表達式呢?

所謂完整表達式,就是指這個表達式不是另一個更大表達式的子表達式。例如,表達式語句中的表達式和while循環中作爲測試的表達式都是完整表達式。

所以:

C 語言

#include <stdio.h>

int main(void) {
    int a = 5;
    while(a-->2) {
        printf("%d\n",a);
    }
    int b = 3;
    if(b-->2){
        printf("%d\n",b);
    }
}
/*
 輸出:
 4
 3
 2
 2
 */
這裏是先算(a-->2)這個完整表達式,當進入循環時,已經退出了這個序列點了,所以所有的副作用都要實現,所以a的值就改變了。

我們在看看其他語言:

C++:

#include <iostream>
using namespace std;

int main(int argc, const char * argv[]) {
    int a = 5;
    while(a-->2){
        cout<<a<<endl;
    }
    int b = 3;
    if(b-->2){
        cout<<b<<endl;
    }
}
/*
 輸出:
 4
 3
 2
 2
 */

JavaScript:

    let a = 5;
    while (a-- > 2) {
        console.log(a);
    }
    let b = 3;
    if (b-- > 2) {
        console.log(b);
    }
    /*
    輸出:
    4
    3
    2
    2
    */



java:

public class Demo {
    public static void main(String[] args) {
        int a = 5;
        while(a-->2) {
            System.out.println(a);
        }
        int b = 3;
        if(b-->2) {
            System.out.println(b);
        }
    }
}
/**
 * 輸出:
 * 4
 * 3
 * 2
 * 2
 */



測試到這裏,上述語言都將循環和條件判斷中的判斷語句視爲完整表達式。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章