文章總列表

嵌入式工程師瑞士刀 (2) C語言函數,為什麼0代表成功,非0代表失敗

緣起

我們Team長得比下圖Aerith妹妹還正的女生問,為什麼C函數回傳值是0代表成功?他覺得回傳1(True)比較符合直覺。所以我決定寫下這篇文章,好好解釋理由傳教用


UNIX命令EXIT Code,以及用途

下圖執行ls用echo $?觀察EXIT code。慣例是:正確執行回傳0;否則回傳非0


ls的手冊也有數值說明


具體EXIT code只是main function回傳值,修改Hello World做實驗,沒什麼神秘

按照此慣例,MAKEFILE執行完指令檢查EXIT code,非0會停下。所以MAKEFILE成功跑完代表大家都回傳0沒遇到錯誤,簡單易懂


回到學妹的問題,為什麼C函數用0代表成功

  1. 最嚴謹的寫法,每個函數都要定義自己的enum標示成功失敗,長得像下面這樣
    enum {
        SUCCESS = x
        FAIL1 = y
        FAIL2 = z
    }

    每個函數的回傳值都要定義對應的enum {},這樣軟體寫起來顯然有點長

    假如只有成功或失敗,大家也接受UNIX慣例,這樣能寫得很精簡
    return 0; // SUCCESS
    return -1; // FAIL

  2. 一般CPU做完運算更新狀態暫存器,內部zero flag代表結果是否為0,所以判斷0是免費的,效能也好。在眾多數值裡也有獨一無二的意義:正確只有一種,但是錯誤卻可能有N種。所以UNIX慣例用0作為成功,也不是隨便亂選

  3. 在組合語言的層級,判斷0與非零會差一道指令,起碼這麼多年,我是這麼認為
    // 0 as SUCCESS, 2 instructions needed
    bl some_function
    cmp r0
    beq  some_label // branch if r0 == 0

    // 1 as SUCCESS, 3 instructions needed
    bl some_function
    ldi r1, #1
    sub r0, r0, r1 // r0 = r0 - r1, extra instruction
    beq some_label // branch if r0 == 0

  4. 下圖在樹莓派做實驗,比對#1,或是#0,指令數一樣多。原因是ARM的cmp指令能把常數編碼進去,不需要多一道指令。現代CPU一般都有這種指令,所以差距不明顯。假如不考慮指令集特異功能,比對0還是效能略好


結論

    正確只能有一種(0),但是錯誤卻可能有多種(non-zero),所以把獨一無二的zero保留給正確,即使效能沒差太多。這個慣例也能用在MAKEFILE串接命令,事情背一種就好,所以我寫軟體也習慣0代表正確

    大多數人不會特別堅持這個事,只要把原因說清楚,大家就能接受了。我相信學妹看完這篇文章,為了避免我再囉唆下去(情緒勒索),就會接受正確要回傳0了


    Reference

    其他在StackOverflow的討論

    留言

    這個網誌中的熱門文章

    幼犬書桌椅選擇心得 升降桌 兒童桌椅

    STM32 UART + DMA,使用HAL實作TX/RX,以及不定長度接收

    CANON G3000 廢墨瓶改裝