The checked
and unchecked
operators are used to control the overflow checking context for integral-type arithmetic operations and conversions.
The checked
operator evaluates the contained expression in a checked context, and the unchecked
operator evaluates the contained expression in an unchecked context. A checked-expression or unchecked-expression corresponds exactly to a parenthesized-expression (§7.5.3), except that the contained expression is evaluated in the given overflow checking context.
The overflow checking context can also be controlled through the checked
and unchecked
statements (§8.11).
The following operations are affected by the overflow checking context established by the checked
and unchecked
operators and statements:
-
unary operator (§7.6.2), when the operand is of an integral type.+
, -
, *
, and /
binary operators (§7.7), when both operands are of integral types.When one of the above operations produce a result that is too large to represent in the destination type, the context in which the operation is performed controls the resulting behavior:
checked
context, if the operation is a constant expression (§7.15), a compile-time error occurs. Otherwise, when the operation is performed at run-time, an OverflowException
is thrown.unchecked
context, the result is truncated by discarding any high-order bits that do not fit in the destination type.When a non-constant expression (an expression that is evaluated at run-time) is not enclosed by any checked
or unchecked
operators or statements, the effect of an overflow during the run-time evaluation of the expression depends on external factors (such as compiler switches and execution environment configuration). The effect is however guaranteed to be either that of a checked
evaluation or that of an unchecked
evaluation.
For constant expressions (expressions that can be fully evaluated at compile-time), the default overflow checking context is always checked
. Unless a constant expression is explicitly placed in an unchecked
context, overflows that occur during the compile-time evaluation of the expression always cause compile-time errors.
In the example
class Test { static int x = 1000000; static int y = 1000000; static int F() { return checked(x * y); // Throws OverflowException } static int G() { return unchecked(x * y); // Returns -727379968 } static int H() { return x * y; // Depends on default } }
no compile-time errors are reported since neither of the expressions can be evaluated at compile-time. At run-time, the F()
method throws an OverflowException
, and the G()
method returns –727379968 (the lower 32 bits of the out-of-range result). The behavior of the H()
method depends on the default overflow checking context for the compilation, but it is either the same as F()
or the same as G()
.
In the example
class Test { const int x = 1000000; const int y = 1000000; static int F() { return checked(x * y); // Compile error, overflow } static int G() { return unchecked(x * y); // Returns -727379968 } static int H() { return x * y; // Compile error, overflow } }
the overflows that occur when evaluating the constant expressions in F()
and H()
cause compile-time errors to be reported because the expressions are evaluated in a checked
context. An overflow also occurs when evaluating the constant expression in G()
, but since the evaluation takes place in an unchecked
context, the overflow is not reported.
The checked
and unchecked
operators only affect the overflow checking context for those operations that are textually contained within the "(
" and ")
" tokens. The operators have no effect on function members that are invoked as a result of evaluating the contained expression. In the example
class Test { static int Multiply(int x, int y) { return x * y; } static int F() { return checked(Multiply(1000000, 1000000)); } }
the use of checked
in F()
does not affect the evaluation of x
*
y
in Multiply()
, and x
*
y
is therefore evaluated in the default overflow checking context.
The unchecked
operator is convenient when writing constants of the signed integral types in hexadecimal notation. For example:
class Test { public const int AllBits = unchecked((int)0xFFFFFFFF); public const int HighBit = unchecked((int)0x80000000); }
Both of the hexadecimal constants above are of type uint
. Because the constants are outside the int
range, without the unchecked
operator, the casts to int
would produce compile-time errors.