int y = -2147483648;
int z = unchecked(y / -1);
The second line causes an OverflowException
. Shouldn't unchecked
prevent this?
For example:
int y = -2147483648;
int z = unchecked(y * 2);
doesn't cause an exception.
int y = -2147483648;
int z = unchecked(y / -1);
The second line causes an OverflowException
. Shouldn't unchecked
prevent this?
For example:
int y = -2147483648;
int z = unchecked(y * 2);
doesn't cause an exception.
This is not an exception that the C# compiler or the jitter have any control over. It is specific to Intel/AMD processors, the CPU generates a #DE trap (Divide Error) when the IDIV instruction fails. The operating system handles the processor trap and reflects it back into the process with a STATUS_INTEGER_OVERFLOW exception. The CLR dutifully translates it to a matching managed exception.
The Intel Processor Manual is not exactly a gold mine of information about it:
Non-integral results are truncated (chopped) towards 0. The remainder is always less than the divisor in magnitude. Overflow is indicated with the #DE (divide error) exception rather than with the CF flag.
In English: the result of the signed division is +2147483648, not representable in an int since it is Int32.MaxValue + 1. Otherwise an inevitable side-effect of the way the processor represents negative values, it uses two's-complement encoding. Which produces a single value to represent 0, leaving an odd number of other possible encodings to represent negative and positive values. There is one more for negative values. Same kind of overflow as -Int32.MinValue
, except that the processor doesn't trap on the NEG instruction and just produces a garbage result.
The C# language is of course not the only one with this problem. The C# Language Spec makes it implementation defined behavior (chapter 7.8.2) by noting the special behavior. No other reasonable thing they could do with it, generating the code to handle the exception surely was considered too unpractical, producing undiagnosably slow code. Not the C# way.
The C and C++ language specs up the ante by making it undefined behavior. That can truly get ugly, like a program compiled with the gcc or g++ compiler, typically with the MinGW toolchain. Which has imperfect runtime support for SEH, it swallows the exception and allows the processor to restart the division instruction. The program hangs, burning 100% core with the processor constantly generating #DE traps. Turning division into the legendary Halt and Catch Fire instruction :)
unchecked
. The fact that C# re-throws the error when the processor throws it doesn't really explain anything. –
Eyeleteer unchecked
is to not throw overflow exceptions when an integer operation overflows, but rather to wrap. –
Eyeleteer neg
on -2147483648 isn't garbage, it is in fact +2147483648 (when interpreted unsigned) –
Degenerate Section 7.72 (Division Operator) of the C# 4 specs states:
If the left operand is the smallest representable int or long value and the right operand is –1, an overflow occurs. In a checked context, [...]. In an unchecked context, it is implementation-defined as to whether a System.ArithmeticException (or a subclass thereof) is thrown or the overflow goes unreported with the resulting value being that of the left operand.
So the fact that this throws an exception in an unchecked context is not in fact a bug, since the behavior is implementation-defined.
int.MinValue
. When writing this C# code you really do need to assume it could have either behavior, you cannot even assume it will throw. –
Eyeleteer int
or long
value and the right operand is –1
, an overflow occurs. A System.OverflowException
is always thrown in this situation, regardless of whether the operation occurs in a checked
or an unchecked
context. –
Mosenthal y
to be a const
, the division is performed at compile-time of course. And the current implementation of the C# compiler allows this (given that you keep the unchecked
keyword explicit); no compile-time error. So you have a situation where removing a const
modifier will change the outcome of the program. The C# compiler and the runtime do not agree on how to divide integers. –
Blaine According to section 7.8.2 of the C# Language Specification 5.0 we have the following case:
7.8.2 Division operator
For an operation of the form x / y, binary operator overload resolution (§7.3.4) is applied to select a specific operator implementation. The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator. The predefined division operators are listed below. The operators all compute the quotient of x and y.
- Integer division:
int operator /(int x, int y);
uint operator /(uint x, uint y);
long operator /(long x, long y);
ulong operator /(ulong x, ulong y);
If the value of the right operand is zero, aSystem.DivideByZeroException
is thrown. The division rounds the result towards zero. Thus the absolute value of the result is the largest possible integer that is less than or equal to the absolute value of the quotient of the two operands. The result is zero or positive when the two operands have the same sign and zero or negative when the two operands have opposite signs. If the left operand is the smallest representable int or long value and the right operand is –1, an overflow occurs. In a checked context, this causes aSystem.ArithmeticException
(or a subclass thereof) to be thrown. In an unchecked context, it is implementation-defined as to whether aSystem.ArithmeticException
(or a subclass thereof) is thrown or the overflow goes unreported with the resulting value being that of the left operand.
© 2022 - 2024 — McMap. All rights reserved.
unchecked
is supposed to avoid overflow exceptions, C# would have to generate code around each unchecked division to check for this specific case before callingidiv
- that would slow down division in unchecked contexts, which would be rather unintuitive, sinceunchecked
is supposed to remove extra checks and improve performance.. – Mescalineunchecked
tag has no mention of C# but instead mentionsjavac
- perhaps it would be a good idea to update the tag excerpt or untag it from this question (I can't do it as I've never used the unchecked keyword). Similarlychecked
is about HTML... – Condom