Udostępnij za pośrednictwem


Ostrzeżenie kompilatora (poziom 4) C4754

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_tobiekt , 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;
}