The checked and unchecked operators are used to control the overflow
checking context for integral-type
arithmetic operations and conversions.
checked-expression:
checked ( expression )
unchecked-expression:
unchecked ( expression )
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 uncheckedexpression
corresponds exactly to a parenthesized-expression (?4.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
(?5.11).
The following operations are affected by the overflow checking context
established by the checked and
unchecked operators and statements:
?The predefined ++ and -- unary operators (?4.5.9 and ?4.6.5), when the
operand is of an integral
type.
?The predefined - unary operator (?4.6.2), when the operand is of an
integral type.
?The predefined +, -, *, and / binary operators (?4.7), when both
operands are of integral types.
?Explicit numeric conversions (?3.2.1) from one integral type to another
integral type, or from float or
double to an integral type.
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:
?In a checked context, if the operation is a constant expression (?4.15),
a compile-time error occurs.
Otherwise, when the operation is performed at run-time, a
System.OverflowException is thrown.
?In an unchecked context, the result is truncated by discarding any
high-order bits that do not fit in the
destination type.
C# LANGUAGE SPECIFICATION
152
For non-constant expressions (expressions that are evaluated at run-time)
that are not enclosed by any
checked or unchecked operators or statements, the default overflow checking
context is unchecked,
unless external factors (such as compiler switches and execution
environment configuration) call for
checked 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 compiletime
errors.
[Note: Developers may benefit if they exercise their code using checked
mode (as well as unchecked mode).
It also seems reasonable that, unless otherwise requested, the default
overflow checking context is set to
checked when debugging is enabled. end note]
[Example: In the example
class Test
{
static readonly int x = 1000000;
static readonly 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 a System.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. end example]
[Example: 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. end example]
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.
[Example: In the example
Chapter 14 Expressions
153
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, so x * y is evaluated in
the default overflow checking context. end example]
The unchecked operator is convenient when writing constants of the signed
integral types in hexadecimal
notation. [Example: 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. end example]
[Note: The checked and unchecked operators and statements allow programmers
to control certain
aspects of some numeric calculations. However, the behavior of some numeric
operators depends on their
operands? data types. For example, multiplying two decimals always results
in an exception on overflow
even within an explicitly unchecked construct. Similarly, multiplying two
floats never results in an
exception on overflow even within an explicitly checked construct. In
addition, other operators are never
affected by the mode of checking, whether default or explicit. As a service
to programmers, it is
recommended that the compiler issue a warning when there is an arithmetic
expression within an explicitly
checked or unchecked context (by operator or statement) that cannot
possibly be affected by the specified
mode of checking. Since such a warning is not required, the compiler has
flexibility in determining the
circumstances that merit the issuance of such warnings. end note]