[英]Distinction between positive and negative overflow in C# arithmetic operation
我在 C#/.NET 中對已檢查的 scope 中的整數執行算術運算,以便在發生溢出時捕獲。 我想以一種簡短、智能、簡單的方式查明溢出是正數還是負數,而不需要根據操作數或操作進行大量特殊情況和檢查。
checked
{
try
{
// The code below is an example operation that will throw an
// overflow exception, that I expect to be a positive overflow.
// In my real code, all arithmetic operations are included in this
// code block and can result in both positive and negative overflows.
int foo = int.MaxValue;
int bar = 1;
foo += bar;
}
catch (OverflowException)
{
// I have found out that a overflow occurred,
// but was it positive or negative?
}
}
可以嗎? 我在異常本身中沒有發現任何信息可用於查找。
我想以一種簡短、智能、簡單的方式查明溢出是正數還是負數,而不需要根據操作數或操作進行大量特殊情況和檢查。
您不能:C# 不會公開該信息,因為:
checked
-with-overflow”表現相同且正確-方向”是不可行的。
一些背景:今天幾乎每個微處理器都有這些特殊功能寄存器(又名CPU 標志,又名狀態寄存器,通常類似於 ARM 中的這 4 個:
當然,ALU(執行算術運算的位)的CS 理論基本設計是這樣的,即 integer 操作是相同的,無論它們是有符號的還是無符號的,正的還是負的(例如減法是負操作數的加法) ),並且標志本身不會自動發出錯誤信號(例如,對於無符號算術,溢出標志被忽略,而進位標志在有符號算術中實際上不如無符號算術重要)。
(這篇文章不會解釋它們代表什么或它們如何工作,因為我假設你,我博學的讀者, 已經熟悉計算機 integer 算術的基本原理)
現在,您可能假設在 C#/.NET 程序的checked
塊中,本機機器代碼將在每次算術運算后檢查這些 CPU 標志的狀態,以查看前一個操作是否有符號溢出或意外的進位 - 如果是這樣,則在調用/跳轉中將該信息傳遞給創建並拋出OverflowException
的 CLR 內部 function。
...在一定程度上就是這樣,只是實際上從 CPU 獲得的有用信息少得令人吃驚。 原因如下:
checked
塊中,CLR 的 JIT 在每條可能溢出的算術指令之后插入一條 x86/x64 jo [CORINFO_HELP_OVERFLOW]
指令。
CORINFO_HELP_OVERFLOW
是本機 function JIT_Overflow
的地址,它(最終)調用RealCOMPlusThrowWorker
以拋出OverflowException
。
請注意, jo
指令只能告訴我們設置了溢出標志:它不會公開或揭示任何其他 CPU 標志的 state,也不會顯示指令操作數的符號,因此無法使用jo
指令判斷溢出是(使用您的術語)“負溢出”還是“正溢出”。
因此,如果程序想要的信息不僅僅是“它溢出了,吉姆”,它需要使用 CPU 指令將 CPU 標志 state 的 rest 保存/復制到 memory 中,如果這些標志不足以確定溢出的方向那么 JIT 編譯器還必須在內存中的某個地方保留所有算術操作數的副本,這在實踐中意味着大幅增加堆棧空間或浪費 CPU 寄存器來保存您不想在算術運算成功之前刪除的舊值。
...不幸的是,用於將 CPU 標志復制到 memory 或其他寄存器的 CPU 指令往往會破壞整體系統性能:
考慮一下現代 CPU 設計的絕對復雜性,以及它們的超標量、推測和亂序執行,以及其他巧妙的小發明: 當程序遵循可預測的“快樂路徑”時,現代 CPU 工作得最好,不使用太多笨拙的指令CPU 內部 state 的亂七八糟。因此,將程序更改為更具內省性不僅會損害您自己程序的性能,還會損害整個計算機系統。 哎呀。
對“進位位”的指令級訪問,以便該值可以用作后續指令的輸入,在計算的早期實現起來很簡單,因為每條指令都在下一條指令開始之前完成。
對於現代的、無序的、超標量處理器實現,成本/收益是相反的; “進位功能”的門成本和/或指令周期減慢遠遠超過任何可能的好處。 這就是為什么 RISC-V 是一種最先進的計算機體系結構,其預期實現范圍從 10k 門復雜度的嵌入式處理器(例如 RV32EC)到具有 100 倍以上門的超標量處理器,但沒有具體化指令-流同步進位。
.NET CLR 表面上是可移植的:.NET 必須在 Windows 支持的每個平台上運行,以及根據微軟 C 級和 D 級的奇思妙想的其他平台:今天它運行在 x86/x64 上, 不同種類的 ARM (包括Apple Silicon ), 過去板谷 c 嗯,雖然 XNA 構建在 Xbox 360 的 PowerPC 芯片上運行,並且 Compact Framework 支持 SH-3/SH-4、MIPS,我敢肯定還有許多其他的。 哦,不要忘記 Silverlight 是如何擁有自己的 CLR 版本的,它最終成為 .NET Core 和現在的 .NET 5 的基礎——它取代了 .NET Framework 4.x——而 Silverlight 也在 2007 年在 PowerPC 上運行。
或者以列表形式,官方.NET CLR 實現支持的所有 ISA 的我頭腦中的列表......我能想到的:
所以這是一個很好的品種 - 我敢肯定還有其他我忘記了,更不用說 Mono 支持的所有平台了。
所有這些處理器/ISA 有什么共同點? 嗯,他們都有自己不同的方式來處理 integer 溢出——有時非常不同。
checked
算術要么。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.