Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Reguły konwersji dla operacji arytmetycznych w porównaniu oznaczają, że nie można wykonać jednej gałęzi.
Ostrzeżenie C4754 jest wystawiane, ponieważ wynik porównania jest zawsze taki sam. Oznacza to, że jedna z gałęzi warunku nigdy nie jest wykonywana, najprawdopodobniej ponieważ skojarzone wyrażenie całkowite jest niepoprawne. Ta usterka kodu często występuje w nieprawidłowych kontrolach przepełnienia liczby całkowitej w architekturach 64-bitowych.
Reguły konwersji liczb całkowitych są złożone i istnieje wiele subtelnych pułapek. Alternatywą dla naprawienia każdego ostrzeżenia C4754 jest zaktualizowanie kodu w celu użycia biblioteki SafeInt.
Przykłady
Ten przykład generuje C4754:
// C4754a.cpp
// Compile with: /W4 /c
#include "errno.h"
int sum_overflow(unsigned long a, unsigned long b)
{
unsigned long long x = a + b; // C4754
if (x > 0xFFFFFFFF)
{
// never executes!
return EOVERFLOW;
}
return 0;
}
Dodanie a + b
może spowodować przepełnienie arytmetyczne, zanim wynik zostanie przekazany do wartości 64-bitowej i przypisany do zmiennej 64-bitowej x
. Oznacza to, że kontrola x
jest nadmiarowa i nigdy nie przechwyci przepełnienia. W takim przypadku kompilator emituje to ostrzeżenie:
Warning C4754: Conversion rules for arithmetic operations in the comparison at C4754a.cpp (7) mean that one branch cannot be executed. Cast '(a + ...)' to 'ULONG64' (or similar type of 8 bytes).
Aby wyeliminować ostrzeżenie, możesz zmienić instrukcję przypisania, aby rzutować operandy na wartości 8-bajtowe:
// Casting one operand is sufficient to force all the operands in
// the addition be upcast according to C/C++ conversion rules, but
// casting both is clearer.
unsigned long long x =
(unsigned long long)a + (unsigned long long)b;
Następny przykład generuje również C4754.
// C4754b.cpp
// Compile with: /W4 /c
#include "errno.h"
int wrap_overflow(unsigned long a)
{
if (a + sizeof(unsigned long) < a) // C4754
{
// never executes!
return EOVERFLOW;
}
return 0;
}
Operator sizeof()
zwraca size_t
obiekt , którego rozmiar jest zależny od architektury. Przykładowy kod działa w architekturze 32-bitowej, w której size_t
typ jest 32-bitowy. Jednak w architekturach 64-bitowych size_t
jest typem 64-bitowym. Reguły konwersji dla liczb całkowitych oznaczają, że a
jest to emisja upcast do wartości 64-bitowej w wyrażeniu a + b < a
tak, jakby została zapisana (size_t)a + (size_t)b < (size_t)a
. Gdy a
i b
są 32-bitowymi liczbami całkowitymi, operacja dodawania 64-bitowego nigdy nie może przepełnić się, a ograniczenie nigdy nie jest przechowywane. W rezultacie kod nigdy nie wykrywa warunku przepełnienia liczby całkowitej w architekturach 64-bitowych. W tym przykładzie kompilator emituje to ostrzeżenie:
Warning C4754: Conversion rules for arithmetic operations in the comparison at C4754b.cpp (7) mean that one branch cannot be executed. Cast '4' to 'ULONG' (or similar type of 4 bytes).
Zwróć uwagę, że komunikat ostrzegawczy jawnie wyświetla stałą wartość 4 zamiast oryginalnego ciągu źródłowego — do czasu, gdy analiza ostrzeżenia napotka kod sizeof(unsigned long)
, została już przekonwertowana na stałą. W związku z tym może być konieczne śledzenie wyrażenia w kodzie źródłowym skojarzonego z stałą wartością w komunikacie ostrzegawczym. Najbardziej typowe źródła kodu rozpoznawane jako stałe w komunikatach ostrzegawczych C4754 to wyrażenia, takie jak sizeof(TYPE)
i strlen(szConstantString)
.
W takim przypadku stały kod będzie podobny do następującego:
// Casting the result of sizeof() to unsigned long ensures
// that all the addition operands are 32-bit, so any overflow
// is detected by the check.
if (a + (unsigned long)sizeof(unsigned long) < a)
Uwaga Numer wiersza określony w ostrzeżeniach kompilatora jest ostatnim wierszem instrukcji. W komunikacie ostrzegawczym dotyczącym złożonej instrukcji warunkowej rozłożonej na wiele wierszy wiersze wierszy z wadą kodu może być kilka wierszy przed zgłoszonym wierszem. Na przykład:
unsigned long a;
if (a + sizeof(unsigned long) < a || // incorrect check
condition1() ||
a == 0) { // C4754 warning reported on this line
// never executes!
return INVALID_PARAMETER;
}