<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

介紹C語言中錯誤處理和異常處理的一些常用的方法和策略

Linux愛好者 ? 來源:良許Linux ? 2024-02-28 14:25 ? 次閱讀

C語言是一種低級的、靜態的、結構化的編程語言,它沒有提供像C++Java等高級語言中的異常處理機制,例如try-catch-finally等。

因此,C語言中的錯誤處理和異常處理需要采用一些其他的方法和策略,以便在程序運行過程中發現、報告和處理錯誤或異常情況,從而保證程序的正確性和穩定性。

本文將介紹C語言中的錯誤處理和異常處理的一些常用的方法和策略,以及如何使用setjmp和longjmp這兩個標準庫函數來實現非局部跳轉,從而在某些情況下模擬異常處理的效果。

錯誤處理和異常處理的概念

在討論C語言中的錯誤處理和異常處理之前,我們先來區分一下錯誤和異常這兩個概念。一般來說,錯誤是指程序中存在的邏輯或語法上的缺陷,導致程序無法按照預期的方式運行或產生正確的結果。

例如,數組越界、空指針解引用、除零操作等都是典型的錯誤。錯誤通常是可以通過修改代碼來避免或修復的。

而異常是指程序在運行過程中遇到了一些意料之外或無法控制的情況,導致程序無法繼續正常運行或完成預期的任務。

例如,文件打開失敗、內存分配失敗、信號中斷等都是典型的異常。異常通常是由于外部環境或系統資源的變化或限制所引起的,不一定是程序本身的缺陷所導致的。

因此,錯誤處理和異常處理有不同的目標和方法。錯誤處理主要是在編碼階段通過檢查代碼邏輯、使用調試工具、進行單元測試等方式來發現并消除錯誤。

而異常處理主要是在運行階段通過檢查函數返回值、使用信號處理函數、設置錯誤處理函數等方式來捕獲并處理異常。

錯誤處理和異常處理的方法和策略

C語言中沒有提供統一的錯誤處理和異常處理機制,但是提供了一些基本的工具和約定,可以根據不同的情況選擇合適的方法和策略來進行錯誤處理和異常處理。以下是一些常用的方法和策略:

檢查函數返回值:這是最常見也最基本的錯誤處理和異常處理方法,就是在調用一個函數后,檢查其返回值是否符合預期或是否表示出錯或失敗。如果出錯或失敗,則根據返回值或者全局變量errno(定義在errno.h頭文件中)來判斷出錯或失敗的原因,并采取相應的措施,例如打印出錯信息、釋放資源、返回錯誤碼等。例如:

#include 
#include 
#include 

int main() {
    // 打開一個文件
    FILE *fp = fopen("test.txt", "r");
    // 檢查文件是否打開成功
    if (fp == NULL) {
        // 打印出錯信息
        perror("fopen");
        // 返回非零值表示出錯
        return 1;
    }
    // 讀取文件內容
    char buf[100];
    // 檢查文件是否讀取成功
    if (fgets(buf, 100, fp) == NULL) {
        // 打印出錯信息
        perror("fgets");
        // 關閉文件
        fclose(fp);
        // 返回非零值表示出錯
        return 2;
    }
    // 打印文件內容
    printf("The content of the file is: %s
", buf);
    // 關閉文件
    fclose(fp);
    // 返回零值表示成功
    return 0;
}

使用assert宏:這是一種用于調試階段的錯誤處理方法,就是在代碼中插入一些斷言,用于檢查程序的某些假設或前提是否成立。如果斷言失敗,則表示程序中存在邏輯錯誤,程序會終止并打印出錯信息。assert宏定義在assert.h頭文件中,其語法為:

assert(expression);

其中expression是一個表達式,如果為真,則繼續執行后面的代碼;如果為假,則終止程序并打印出錯信息。例如:

#include 
#include 

int main() {
    // 定義一個變量
    int x = 10;
    // 斷言x大于0
    assert(x > 0);
    // 打印x的值
    printf("x is %d
", x);
    // 修改x的值
    x = -10;
    // 斷言x大于0
    assert(x > 0);
    // 打印x的值
    printf("x is %d
", x);
    return 0;
}

輸出:

x is 10
Assertion failed: (x > 0), function main, file test.c, line 15.
Abort trap: 6

可以看到,當第二個斷言失敗時,程序就終止了,并打印了出錯信息,包括斷言的表達式、函數名、文件名和行號。這樣可以方便地定位錯誤的位置和原因。需要注意的是,assert宏只在調試階段有效,如果在編譯時定義了宏NDEBUG,則assert宏會被忽略,不會對程序產生任何影響。例如:

gcc -DNDEBUG test.c -o test

這樣編譯后,即使斷言失敗,程序也不會終止,而是繼續執行后面的代碼。

使用信號處理函數:這是一種用于處理運行時異常的方法,就是在程序中注冊一些信號處理函數,用于響應系統或用戶發送的一些信號。信號是一種軟件中斷,用于通知進程發生了某些異?;蚴录?。例如,當程序試圖訪問非法內存地址時,系統會發送SIGSEGV信號;當用戶按下Ctrl-C鍵時,系統會發送SIGINT信號;當程序執行除零操作時,系統會發送SIGFPE信號等。C語言提供了signal函數來設置信號處理函數,其語法為:

void (*signal(int signum, void (*handler)(int)))(int);

其中signum是要處理的信號的編號,handler是要設置的信號處理函數的指針。如果handler為SIG_IGN,則表示忽略該信號;如果handler為SIG_DFL,則表示恢復該信號的默認處理方式。signal函數返回一個指針,指向之前設置的信號處理函數。例如:

#include 
#include 

// 定義一個信號處理函數
void handler(int signum) {
    // 打印收到的信號編號
    printf("Received signal %d
", signum);
}

int main() {
    // 設置SIGINT信號的處理函數為handler
    signal(SIGINT, handler);
    // 循環等待用戶輸入
    while (1) {
        char c = getchar();
        // 如果輸入q,則退出循環
        if (c == 'q') {
            break;
        }
    }
    return 0;
}

運行結果:

^CReceived signal 2
^CReceived signal 2
q

可以看到,當用戶按下Ctrl-C鍵時,程序不會終止,而是調用了自定義的信號處理函數,并打印了收到的信號編號(2表示SIGINT)。當用戶輸入q時,程序才退出循環。

使用setjmp和longjmp函數:這是一種用于實現非局部跳轉的方法,就是在程序中設置一個跳轉點,并在某些情況下跳轉到該跳轉點,從而繞過中間的一些代碼或函數。這樣可以在某些情況下模擬異常處理的效果,例如在發生錯誤或異常時,直接跳轉到錯誤處理或資源釋放的代碼,而不需要逐層返回。setjmp和longjmp函數定義在setjmp.h頭文件中,其語法為:

int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);

其中env是一個用于存儲跳轉點信息的數據類型,它實際上是一個數組,包含了程序計數器、棧指針、寄存器等信息。val是一個用于傳遞跳轉原因的整數值,它不能為0。setjmp函數用于設置跳轉點,并返回0;longjmp函數用于跳轉到跳轉點,并使setjmp函數返回val。例如:

#include 
#include 

// 定義一個全局的env變量
jmp_buf env;

// 定義一個可能發生錯誤的函數
void foo(int x) {
    // 如果x為0,則發生除零錯誤,跳轉到env,并傳遞1
    if (x == 0) {
        longjmp(env, 1);
    }
    // 否則,正常執行,并打印結果
    printf("100 / %d = %d
", x, 100 / x);
}

int main() {
    // 設置跳轉點,并接收返回值
    int ret = setjmp(env);
    // 如果返回值為0,則表示正常執行
    if (ret == 0) {
        // 調用foo函數,傳入一個非零值
        foo(10);
        // 調用foo函數,傳入一個零值
        foo(0);
    } else {
        // 如果返回值不為0,則表示發生錯誤或異常,根據返回值打印出錯信息
        switch (ret) {
            case 1:
                printf("Error: division by zero
");
                break;
            default:
                printf("Unknown error
");
                break;
        }
    }
    return 0;
}

輸出:

100 / 10 = 10
Error: division by zero

可以看到,當調用foo函數時,如果傳入的參數為0,則會觸發longjmp函數,從而跳轉到setjmp函數所在的位置,并使setjmp函數返回1。這樣就可以根據返回值來判斷發生了什么錯誤或異常,并進行相應的處理。需要注意的是,使用setjmp和longjmp函數時要遵循一些規則和限制,例如:

不要在setjmp和longjmp之間修改env變量的內容。

不要在setjmp和longjmp之間修改任何具有全局或靜態存儲期的變量。

不要在setjmp和longjmp之間調用任何可能改變程序狀態或資源的函數。

不要在多線程環境中使用setjmp和longjmp函數。

總結

C語言中的錯誤處理和異常處理需要采用一些其他的方法和策略,以便在程序運行過程中發現、報告和處理錯誤或異常情況,從而保證程序的正確性和穩定性。

本文介紹了C語言中的錯誤處理和異常處理的一些常用的方法和策略,以及如何使用setjmp和longjmp函數來實現非局部跳轉,從而在某些情況下模擬異常處理的效果。希望這些內容能夠對你有所幫助,在C語言中更好地進行錯誤處理和異常處理。




審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 寄存器
    +關注

    關注

    30

    文章

    5141

    瀏覽量

    118055
  • 信號處理
    +關注

    關注

    47

    文章

    877

    瀏覽量

    102628
  • JAVA
    +關注

    關注

    19

    文章

    2908

    瀏覽量

    103134
  • 計數器
    +關注

    關注

    32

    文章

    2199

    瀏覽量

    93299
  • C語言
    +關注

    關注

    180

    文章

    7542

    瀏覽量

    131032

原文標題:C語言錯誤處理和異常處理方法和策略,如何實現非局部跳轉

文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    嵌入式編程錯誤處理機制設計

    本文主要總結嵌入式系統C語言編程中,主要的錯誤處理方式。文中涉及的代碼運行環境如下。
    發表于 04-28 09:59 ?583次閱讀
    嵌入式編程<b class='flag-5'>錯誤處理</b>機制設計

    嵌入式系統C語言編程中主要的錯誤處理方式

    本文主要總結嵌入式系統C語言編程中,主要的錯誤處理方式。
    發表于 07-24 16:40 ?580次閱讀
    嵌入式系統C<b class='flag-5'>語言</b>編程中主要的<b class='flag-5'>錯誤處理</b>方式

    Rust語言中錯誤處理的機制

    可能的錯誤,實際運行中仍然可能出現各種各樣的錯誤,比如文件不存在、網絡連接失敗等等。對于這些不可預測的錯誤,我們必須使用錯誤處理機制來進行處理
    的頭像 發表于 09-19 14:54 ?829次閱讀

    labviEW錯誤處理的問題

    為什么這個程序在啟用自動錯誤處理C:\data.txt不存在的情況下,沒有顯示錯誤對話框???
    發表于 04-01 10:03

    AF錯誤處理

    想問下關于AF的錯誤處理,例如我進行串口通訊,打開串口錯誤,但是我不想停止AF,想繼續嘗試連接要怎么做?
    發表于 02-03 15:44

    C語言和匯編語言混合編程方法和C語言中處理方法

    C語言和匯編語言混合編程方法和C語言中處理方法,new
    發表于 01-06 14:36 ?36次下載

    LabVIEW中的錯誤處理

    如何合理使用 LabVIEW 中的自定義錯誤處理功能;對于可預見的錯誤,是否可以選擇直 接忽略,或者前幾次嘗試忽略直到該特定錯誤出現很多次后才通知用戶需要糾正該錯誤 了;是否可以對
    發表于 05-24 11:07 ?6次下載

    Spring Boot框架錯誤處理

    》 《strong》翻譯《/strong》:雁驚寒《/p》 《/blockquote》《p》《em》摘要:本文通過實例介紹了使用Spring Boot在設計API的時候如何正確地對異常進行處理。以下是譯文《/em》《/p》《p》
    發表于 09-28 15:31 ?0次下載

    嵌入式系統C語言編程中的錯誤處理資料總結

    本文主要總結嵌入式系統C語言編程中,主要的錯誤處理方式。文中涉及的代碼運行環境如下:
    發表于 11-28 10:39 ?1775次閱讀

    Rust代碼啟發之返回值異常錯誤處理

    這樣的代碼,錯誤處理代碼和業務邏輯交織在一起,也容易忽略處理錯誤。以及把返回值只用于錯誤返回,有點浪費的感覺。因為很多時候把計算結果作為返回值,更符合思考的邏輯。
    的頭像 發表于 09-22 09:24 ?1703次閱讀
    Rust代碼啟發之返回值<b class='flag-5'>異常</b><b class='flag-5'>錯誤處理</b>

    異常處理錯誤碼管理

    團隊達成共識,統一規范就可以。 下面介紹一下我使用的處理異常的方式。 自定義異常 創建一個業務異常基類 BaseException exte
    的頭像 發表于 09-25 14:51 ?395次閱讀
    <b class='flag-5'>異常</b><b class='flag-5'>處理</b>和<b class='flag-5'>錯誤</b>碼管理

    RS232通信時怎么處理錯誤?RS232通信中的錯誤處理方法

    錯誤是RS232通信中非常重要的一個部分。下面介紹一些處理RS232通信錯誤方法。 1. 校驗
    的頭像 發表于 10-17 16:33 ?1953次閱讀

    Service層的異常處理

    一般初學者學習編碼和[錯誤處理]時,先知道[編程語言]有一種處理錯誤的形式或約定(如Java就拋異常),然后就開始用這些工具。但卻忽視這問題
    的頭像 發表于 01-08 11:29 ?278次閱讀

    如何解決C語言中的“訪問權限沖突”異常?C語言引發異常原因分析

    一些措施來解決和防止其發生。本文將詳細介紹C語言中訪問權限沖突異常的原因以及解決方法。 一、訪問權限沖突
    的頭像 發表于 01-12 16:03 ?1617次閱讀

    C語言中錯誤處理機制解析

    C 語言不提供對錯誤處理的直接支持,但是作為一種系統編程語言,它以返回值的形式允許您訪問底層數據。
    的頭像 發表于 02-26 11:19 ?265次閱讀
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>