簡體   English   中英

如何在 C 和 C++ 中捕獲運行時錯誤?

[英]How to catch run time error in C and C++?

就像修改CONST int一樣,

我可以注冊一個特定的 function 來處理運行時錯誤,這樣這種操作就會失敗而不是終止應用程序嗎?

如果您的意思是 C++,則有一個名為runtime_error的異常 class 。 您可以使用 catch 子句捕獲它:

catch(std::runtime_error& e) {}

但是,C 和 C++ 中的許多事情(例如修改 const int)會導致未定義的行為 您無法在運行時捕獲它們。 您無法捕獲它們,因為沒有拋出異常(從技術上講,任何事情都可能發生,包括拋出異常(僅限 C++),但這不是您可以或不應該希望的)。

解決方案是編寫干凈安全的代碼。 為此,許多書中列出了許多建議。 :)

根據規范,修改const是“未定義的行為”,因此編譯器可以做任何事情。 在實踐中,許多實現有時會為此類代碼生成運行時錯誤,但很多不會。 它通常取決於程序的性質。 這是一個插圖:

#include <stdio.h>
#include <string.h>

typedef int (*fn)(const char *);

extern const fn global_fn_ptr;
extern const char global_string[];
const fn global_fn_ptr = puts;
const char global_string[] = "hello";

int main(int argc, char *argv[])
{
    puts("Setting global_fn_ptr to NULL");
    *(fn *)&global_fn_ptr = NULL;
    puts("Setting string to \"bye\"");
    strcpy((char *)global_string, "bye");
    return 0;
}

在我的系統上,我通過修改字符串獲得了 SIGBUS,但修改 function 工作正常。 這是由於 function 指針的特殊性質,其值並不總是在運行時確定,因此該值必須存儲在可寫的 memory 中。

在 C++ 中捕獲 SIGBUS 或 SIGSEGV 並將其轉換為異常通常是不安全的。 從信號處理程序中正確地longjmp也是非常困難的——在 C 中使用這種模式的代碼中有一半可能是不正確的。 最安全的選擇是讓程序立即終止,或者如果您真的需要運行時的這種幫助,請非常小心地使用 C 代碼,以便您可以在非本地退出中釋放適當的資源 - C++ 不會這樣做,因為longjmp贏了不要調用析構函數。

或者您可以直接轉到 C# 或 Java,它們都有為您執行此操作的運行時以及之后清理的垃圾收集器。

這是特定於操作系統的。 語言本身將這些指定為未定義的行為。

在與 POSIX 兼容的操作系統中,您的程序可以在 memory 訪問受限的情況下捕獲SIGSEGV信號,在無效指令的情況下捕獲SIGILL信號,在非法浮點運算(例如被零除)的情況下捕獲SIGFPE

在 C 中,運行時錯誤通常會生成可由信號處理程序處理的信號。

在 C++ 中,運行時錯誤也可以作為可以在 try/catch 塊中捕獲的異常拋出。

要在某個時刻繼續而不是崩潰,您需要在信號處理程序中使用 setjmp/longjmp - 從程序錯誤中捕獲信號后返回是不安全的

我大錯特錯。

嘗試修改 const 限定的變量確實是未定義的行為,而且似乎已經有好幾年了。 它可能會也可能不會產生運行時錯誤; 能不能用得看平台。

正如@Dietrich Epp 耐心指出的那樣,n1570 是 C 標准下一次迭代的委員會草案,在第 6.7.3 節中給出了規則。 自 C89 以來,該部分的措辭可能沒有改變。

我非常抱歉以其他方式提出索賠; 以及侮辱這個群體的成員。 尤其是迪特里希。

現在,我在哪里可以找到一些美味的散養烏鴉?

您必須知道這一點,並且一定是您的示例考慮不當,但是無論如何都值得注意,以防有人誤解:

在 C 中,在運行時沒有const int (或const其他任何東西)這樣的東西; const純粹是一個編譯時概念。 因此,修改const int沒有運行時錯誤。

如果我理解正確,您所談論的場景是(通常)根據語言未定義的場景。

這些情況會導致不可預知的結果,正如您所指出的,這些結果有時可能包括程序繼續運行並看起來“工作”,或者它可能會崩潰,或者鼻惡魔可能會自發地出現。

如果您想捕捉未定義行為的使用,那么您可以在某些情況下使用工具來執行此操作。

例如, Electric Fence非常擅長揭示您不應該寫入 memory 的位置(盡管不要在發布版本中激活它。)。 這是否適用於寫入您拋棄的const的東西將取決於應用了哪些優化; object可能具有可寫的 memory,並且在物理上無法確定您實際上做錯了什么。

你不會得到一個整潔的語言層異常。 由於無論如何您都將不得不在工具路線上使用 go,因此只需盡可能應用 static 和動態分析工具並配置文件 沒有萬無一失的方法可以突然打開“理智地通知我所有未定義行為的使用”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM