From ab53c14e9dca8554c473fecb62635d826da0892b Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 30 Oct 2024 09:39:50 -0400 Subject: [PATCH 1/3] clarify non-integral behavior Fixes #42428 Clarify that `checked` and `unchecked` behavior changes for floating point types (`float`, `double`, and `half`), and has minimal impact for `decimal`. --- .../statements/checked-and-unchecked.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/docs/csharp/language-reference/statements/checked-and-unchecked.md b/docs/csharp/language-reference/statements/checked-and-unchecked.md index ec5fd964156e6..61e1d398e590c 100644 --- a/docs/csharp/language-reference/statements/checked-and-unchecked.md +++ b/docs/csharp/language-reference/statements/checked-and-unchecked.md @@ -1,7 +1,7 @@ --- -title: "checked and unchecked statements - control the overflow-checking context" -description: "The `checked` and `unchecked` statements control the overflow-checking context. In a checked context, overflow causes an exception to be thrown. In an unchecked context, the result is truncated." -ms.date: 11/22/2022 +title: "checked, unchecked statements - overflow-checking context" +description: "Control the overflow-checking context. In a checked context, overflow causes an exception to be thrown. In an unchecked context, the result is truncated." +ms.date: 10/29/2022 f1_keywords: - "checked_CSharpKeyword" - "unchecked_CSharpKeyword" @@ -32,6 +32,16 @@ The `checked` and `unchecked` statements and operators only affect the overflow- At the preceding example, the first invocation of the `Multiply` local function shows that the `checked` statement doesn't affect the overflow-checking context within the `Multiply` function as no exception is thrown. At the second invocation of the `Multiply` function, the expression that calculates the second argument of the function is evaluated in a checked context and results in an exception as it's textually inside the block of the `checked` statement. +The behavior of `checked` and `unchecked` depends on the type and the operation. Even for integers, things like `unchecked(x / 0)` will always throw because there is no sensible behavior. Developers need to check the behavior for the type being used and the operation being done to understand how the `checked` and `unchecked` keywords will impact their code. + +## Numeric types and overflow-checking context + +The `checked` and `unchecked` primarily apply to integral types where there is a sensible overflow behavior. The wraparound behavior where `T.MaxValue + 1` becomes `T.MinValue` is sensible in a two's complement value. The represented value is not *correct* since it cannot fit in the storage for the type. Therefore, the bits are representative of the lower n-bits of the full result. + +For types like `decimal`, `float`, `double` or `Half` where you have a more complex value being represented or a one's complement representation, wraparound no longer becomes sensible. It can't be used to compute larger or more accurate results, so `unchecked` isn't beneficial. + +For `float`, `double`, and `Half` you do have sensible saturating values for `PositiveInfinity` and `NegativeInfinity` so you can detect overflow in an `unchecked` context. For `decimal`, no such limits exist and saturating at `MaxValue` can lead to errors or confusion, so operations using those types throw in both a `checked` and `unchecked` context. + ## Operations affected by the overflow-checking context The overflow-checking context affects the following operations: From 866a0e10e6ba074c43aea7dd5c2464c2e0bb80ca Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 30 Oct 2024 09:44:16 -0400 Subject: [PATCH 2/3] edit pass --- .../statements/checked-and-unchecked.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/csharp/language-reference/statements/checked-and-unchecked.md b/docs/csharp/language-reference/statements/checked-and-unchecked.md index 61e1d398e590c..480bbf57d8e4c 100644 --- a/docs/csharp/language-reference/statements/checked-and-unchecked.md +++ b/docs/csharp/language-reference/statements/checked-and-unchecked.md @@ -1,5 +1,5 @@ --- -title: "checked, unchecked statements - overflow-checking context" +title: "The checked and unchecked statements - overflow-checking" description: "Control the overflow-checking context. In a checked context, overflow causes an exception to be thrown. In an unchecked context, the result is truncated." ms.date: 10/29/2022 f1_keywords: @@ -11,14 +11,14 @@ helpviewer_keywords: - "statements [C#], checked and unchecked" - "overflow checking [C#]" --- -# checked and unchecked statements (C# reference) +# The checked and unchecked statements (C# reference) -The `checked` and `unchecked` statements specify the overflow-checking context for integral-type arithmetic operations and conversions. When integer arithmetic overflow occurs, the overflow-checking context defines what happens. In a checked context, a is thrown; if overflow happens in a constant expression, a compile-time error occurs. In an unchecked context, the operation result is truncated by discarding any high-order bits that don't fit in the destination type. For example, in the case of addition it wraps from the maximum value to the minimum value. The following example shows the same operation in both a checked and unchecked context: +The `checked` and `unchecked` statements specify the overflow-checking context for integral-type arithmetic operations and conversions. When integer arithmetic overflow occurs, the overflow-checking context defines what happens. In a checked context, a is thrown; if overflow happens in a constant expression, a compile-time error occurs. In an unchecked context, the operation result is truncated by discarding any high-order bits that don't fit in the destination type. For example, addition wraps from the maximum value to the minimum value. The following example shows the same operation in both a checked and unchecked context: :::code language="csharp" interactive="try-dotnet-method" source="snippets/checked-and-unchecked/Program.cs" id="MainExample"::: > [!NOTE] -> The behavior of *user-defined* operators and conversions in the case of overflow can differ from the one described in the preceding paragraph. In particular, [user-defined checked operators](../operators/arithmetic-operators.md#user-defined-checked-operators) might not throw an exception in a checked context. +> The overflow behavior of *user-defined* operators and conversions can differ from the one described in the preceding paragraph. In particular, [user-defined checked operators](../operators/arithmetic-operators.md#user-defined-checked-operators) might not throw an exception in a checked context. For more information, see the [Arithmetic overflow and division by zero](../operators/arithmetic-operators.md#arithmetic-overflow-and-division-by-zero) and [User-defined checked operators](../operators/arithmetic-operators.md#user-defined-checked-operators) sections of the [Arithmetic operators](../operators/arithmetic-operators.md) article. @@ -32,13 +32,13 @@ The `checked` and `unchecked` statements and operators only affect the overflow- At the preceding example, the first invocation of the `Multiply` local function shows that the `checked` statement doesn't affect the overflow-checking context within the `Multiply` function as no exception is thrown. At the second invocation of the `Multiply` function, the expression that calculates the second argument of the function is evaluated in a checked context and results in an exception as it's textually inside the block of the `checked` statement. -The behavior of `checked` and `unchecked` depends on the type and the operation. Even for integers, things like `unchecked(x / 0)` will always throw because there is no sensible behavior. Developers need to check the behavior for the type being used and the operation being done to understand how the `checked` and `unchecked` keywords will impact their code. +The behavior of `checked` and `unchecked` depends on the type and the operation. Even for integers, operations like `unchecked(x / 0)` always throws because there's no sensible behavior. Developers need to check the behavior for the type and the operation to understand how the `checked` and `unchecked` keywords affect their code. ## Numeric types and overflow-checking context -The `checked` and `unchecked` primarily apply to integral types where there is a sensible overflow behavior. The wraparound behavior where `T.MaxValue + 1` becomes `T.MinValue` is sensible in a two's complement value. The represented value is not *correct* since it cannot fit in the storage for the type. Therefore, the bits are representative of the lower n-bits of the full result. +The `checked` and `unchecked` primarily apply to integral types where there's a sensible overflow behavior. The wraparound behavior where `T.MaxValue + 1` becomes `T.MinValue` is sensible in a two's complement value. The represented value isn't *correct* since it can't fit in the storage for the type. Therefore, the bits are representative of the lower n-bits of the full result. -For types like `decimal`, `float`, `double` or `Half` where you have a more complex value being represented or a one's complement representation, wraparound no longer becomes sensible. It can't be used to compute larger or more accurate results, so `unchecked` isn't beneficial. +For types like `decimal`, `float`, `double`, or `Half` where you have a more complex value being represented or a one's complement representation, wraparound no longer becomes sensible. It can't be used to compute larger or more accurate results, so `unchecked` isn't beneficial. For `float`, `double`, and `Half` you do have sensible saturating values for `PositiveInfinity` and `NegativeInfinity` so you can detect overflow in an `unchecked` context. For `decimal`, no such limits exist and saturating at `MaxValue` can lead to errors or confusion, so operations using those types throw in both a `checked` and `unchecked` context. @@ -56,9 +56,9 @@ The overflow-checking context affects the following operations: ## Default overflow-checking context -If you don't specify the overflow-checking context, the value of the [**CheckForOverflowUnderflow**](../compiler-options/language.md#checkforoverflowunderflow) compiler option defines the default context for non-constant expressions. By default the value of that option is unset and integral-type arithmetic operations and conversions are executed in an **unchecked** context. +If you don't specify the overflow-checking context, the value of the [**CheckForOverflowUnderflow**](../compiler-options/language.md#checkforoverflowunderflow) compiler option defines the default context for nonconstant expressions. By default the value of that option is unset and integral-type arithmetic operations and conversions are executed in an **unchecked** context. -Constant expressions are evaluated by default in a checked context and a compile-time error occurs in the case of overflow. You can explicitly specify an unchecked context for a constant expression with the `unchecked` statement or operator. +Constant expressions are evaluated by default in a checked context and overflow causes a compile-time error. You can explicitly specify an unchecked context for a constant expression with the `unchecked` statement or operator. ## C# language specification From ac3efeb4c58c67de134bdb639c72533ee50e3aca Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 31 Oct 2024 09:41:28 -0400 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: Genevieve Warren <24882762+gewarren@users.noreply.github.com> --- .../statements/checked-and-unchecked.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/csharp/language-reference/statements/checked-and-unchecked.md b/docs/csharp/language-reference/statements/checked-and-unchecked.md index 480bbf57d8e4c..76dc7d1303a0a 100644 --- a/docs/csharp/language-reference/statements/checked-and-unchecked.md +++ b/docs/csharp/language-reference/statements/checked-and-unchecked.md @@ -32,15 +32,15 @@ The `checked` and `unchecked` statements and operators only affect the overflow- At the preceding example, the first invocation of the `Multiply` local function shows that the `checked` statement doesn't affect the overflow-checking context within the `Multiply` function as no exception is thrown. At the second invocation of the `Multiply` function, the expression that calculates the second argument of the function is evaluated in a checked context and results in an exception as it's textually inside the block of the `checked` statement. -The behavior of `checked` and `unchecked` depends on the type and the operation. Even for integers, operations like `unchecked(x / 0)` always throws because there's no sensible behavior. Developers need to check the behavior for the type and the operation to understand how the `checked` and `unchecked` keywords affect their code. +The behavior of `checked` and `unchecked` depends on the type and the operation. Even for integers, operations like `unchecked(x / 0)` always throw because there's no sensible behavior. Check the behavior for the type and the operation to understand how the `checked` and `unchecked` keywords affect your code. ## Numeric types and overflow-checking context -The `checked` and `unchecked` primarily apply to integral types where there's a sensible overflow behavior. The wraparound behavior where `T.MaxValue + 1` becomes `T.MinValue` is sensible in a two's complement value. The represented value isn't *correct* since it can't fit in the storage for the type. Therefore, the bits are representative of the lower n-bits of the full result. +The `checked` and `unchecked` keywords primarily apply to integral types where there's a sensible overflow behavior. The wraparound behavior where `T.MaxValue + 1` becomes `T.MinValue` is sensible in a two's complement value. The represented value isn't *correct* since it can't fit in the storage for the type. Therefore, the bits are representative of the lower n-bits of the full result. -For types like `decimal`, `float`, `double`, or `Half` where you have a more complex value being represented or a one's complement representation, wraparound no longer becomes sensible. It can't be used to compute larger or more accurate results, so `unchecked` isn't beneficial. +For types like `decimal`, `float`, `double`, and `Half` that represent a more complex value or a one's complement value, wraparound isn't sensible. It can't be used to compute larger or more accurate results, so `unchecked` isn't beneficial. -For `float`, `double`, and `Half` you do have sensible saturating values for `PositiveInfinity` and `NegativeInfinity` so you can detect overflow in an `unchecked` context. For `decimal`, no such limits exist and saturating at `MaxValue` can lead to errors or confusion, so operations using those types throw in both a `checked` and `unchecked` context. +`float`, `double`, and `Half` have sensible saturating values for `PositiveInfinity` and `NegativeInfinity`, so you can detect overflow in an `unchecked` context. For `decimal`, no such limits exist, and saturating at `MaxValue` can lead to errors or confusion. Operations that use `decimal` throw in both a `checked` and `unchecked` context. ## Operations affected by the overflow-checking context