Zaznaczone i niezaznaczone instrukcje (odwołanie w C#)
Instrukcje checked
i unchecked
określają kontekst sprawdzania przepełnienia dla operacji arytmetycznych i konwersji typu całkowitego. Gdy występuje przepełnienie arytmetyczne liczb całkowitych, kontekst sprawdzania przepełnienia definiuje, co się dzieje. W zaznaczonym kontekście System.OverflowException jest zgłaszany element . Jeśli przepełnienie występuje w wyrażeniu stałym, wystąpi błąd czasu kompilacji. W niezaznaczonym kontekście wynik operacji jest obcinany przez odrzucenie wszystkich bitów o wysokiej kolejności, które nie mieszczą się w typie docelowym. Na przykład dodanie zawija się z maksymalnej wartości do wartości minimalnej. W poniższym przykładzie pokazano tę samą operację zarówno w kontekście zaznaczonym, jak i niezaznaczonej:
uint a = uint.MaxValue;
unchecked
{
Console.WriteLine(a + 3); // output: 2
}
try
{
checked
{
Console.WriteLine(a + 3);
}
}
catch (OverflowException e)
{
Console.WriteLine(e.Message); // output: Arithmetic operation resulted in an overflow.
}
Uwaga
Zachowanie przepełnienia operatorów zdefiniowanych przez użytkownika i konwersji może różnić się od tego, który został opisany w poprzednim akapicie. W szczególności operatory sprawdzane przez użytkownika mogą nie zgłaszać wyjątku w zaznaczonym kontekście.
Aby uzyskać więcej informacji, zobacz sekcje Przepełnienie arytmetyczne i dzielenie według zera i Operatory sprawdzone zdefiniowane przez użytkownika w artykule Operatory arytmetyczne.
Aby określić kontekst sprawdzania przepełnienia dla wyrażenia, można również użyć checked
operatorów i unchecked
, jak pokazano w poniższym przykładzie:
double a = double.MaxValue;
int b = unchecked((int)a);
Console.WriteLine(b); // output: -2147483648
try
{
b = checked((int)a);
}
catch (OverflowException e)
{
Console.WriteLine(e.Message); // output: Arithmetic operation resulted in an overflow.
}
Instrukcje checked
i unchecked
i operatory mają wpływ tylko na kontekst sprawdzania przepełnienia dla tych operacji, które są tekstowo wewnątrz bloku instrukcji lub nawiasów operatora, jak pokazano w poniższym przykładzie:
int Multiply(int a, int b) => a * b;
int factor = 2;
try
{
checked
{
Console.WriteLine(Multiply(factor, int.MaxValue)); // output: -2
}
}
catch (OverflowException e)
{
Console.WriteLine(e.Message);
}
try
{
checked
{
Console.WriteLine(Multiply(factor, factor * int.MaxValue));
}
}
catch (OverflowException e)
{
Console.WriteLine(e.Message); // output: Arithmetic operation resulted in an overflow.
}
W poprzednim przykładzie pierwsze wywołanie Multiply
funkcji lokalnej pokazuje, że checked
instrukcja nie ma wpływu na kontekst sprawdzania przepełnienia w Multiply
ramach funkcji, ponieważ nie jest zgłaszany żaden wyjątek. Podczas drugiego Multiply
wywołania funkcji wyrażenie, które oblicza drugi argument funkcji, jest obliczane w kontekście sprawdzanym i powoduje wyjątek, ponieważ jest tekstowo wewnątrz bloku checked
instrukcji .
Zachowanie i checked
unchecked
zależy od typu i operacji. Nawet w przypadku liczb całkowitych operacje takie jak unchecked(x / 0)
zawsze zgłaszane, ponieważ nie ma rozsądnego zachowania. Sprawdź zachowanie typu i operacji, aby zrozumieć, jak słowa checked
kluczowe i unchecked
wpływają na kod.
Typy liczbowe i kontekst sprawdzania przepełnienia
Słowa checked
kluczowe i unchecked
dotyczą głównie typów całkowitych, w których występuje rozsądne zachowanie przepełnienia. Zachowanie zawijania, w którym T.MaxValue + 1
staje się T.MinValue
rozsądne w wartości uzupełniającej dwóch. Reprezentowana wartość nie jest poprawna , ponieważ nie może zmieścić się w magazynie dla typu. W związku z tym bity są reprezentatywne dla niższych n-bitów pełnego wyniku.
W przypadku typów, takich jak decimal
, float
, double
i Half
reprezentujących bardziej złożoną wartość lub wartość uzupełniającą, zawijanie nie jest rozsądne. Nie można jej używać do obliczania większych lub bardziej dokładnych wyników, więc unchecked
nie jest korzystne.
float
, double
i Half
mają rozsądne wartości saturujące dla PositiveInfinity
i NegativeInfinity
, dzięki czemu można wykryć przepełnienie w unchecked
kontekście. W przypadku decimal
programu nie istnieją takie limity, a saturacja w MaxValue
programie może prowadzić do błędów lub nieporozumień. Operacje używające decimal
rzutu zarówno w kontekście, jak i checked
unchecked
.
Operacje, na które ma wpływ kontekst sprawdzania przepełnienia
Kontekst sprawdzania przepełnienia ma wpływ na następujące operacje:
Następujące wbudowane operatory arytmetyczne: jednoargumentowe
++
,--
-
i binarne ,-
*
, i/
operatory, gdy ich operandy są typu całkowitego (czyli całkowitego+
typu liczbowego lub char) lub typu wyliczenia.Jawne konwersje liczbowe między typami całkowitymi lub z
float
lubdouble
do typu całkowitego.Uwaga
Podczas konwertowania
decimal
wartości na typ całkowity i wynik znajduje się poza zakresem typu docelowego, element jest zawsze zgłaszany, OverflowException niezależnie od kontekstu sprawdzania przepełnienia.Począwszy od języka C# 11, zdefiniowane przez użytkownika operatory i konwersje. Aby uzyskać więcej informacji, zobacz sekcję Operatory zaznaczone przez użytkownika w artykule Operatory arytmetyczne.
Domyślny kontekst sprawdzania przepełnienia
Jeśli nie określisz kontekstu sprawdzania przepełnienia, wartość opcji kompilatora CheckForOverflowUnderflow definiuje domyślny kontekst dla wyrażeń niezdecydowanych. Domyślnie wartość tej opcji jest niezwiązana, a operacje arytmetyczne i konwersje typu całkowitego są wykonywane w nieznakowanym kontekście.
Wyrażenia stałe są domyślnie oceniane w zaznaczonym kontekście i przepełnienie powoduje błąd czasu kompilacji. Można jawnie określić nieznakowany kontekst dla wyrażenia stałego za pomocą instrukcji unchecked
lub operatora.
specyfikacja języka C#
Aby uzyskać więcej informacji, zobacz następujące sekcje specyfikacji języka C#:
- Zaznaczone i niezaznaczone instrukcje
- Zaznaczone i niezaznaczone operatory
- Operatory zdefiniowane przez użytkownika i niezaznaczone — C# 11