Udostępnij za pośrednictwem


Potwierdzenia C/C++

Instrukcję potwierdzenia Określa, że warunek, które mają być spełnione w momencie w programie.Jeśli warunek ten nie zostanie spełniony, twierdzenie nie powiedzie się, wykonanie programu zostanie przerwana, a okno dialogowe Assertion Failed pojawia się.

Visual C++ obsługuje potwierdzenia instrukcji, które są oparte na następujące konstrukcje:

  • Twierdzenia MFC dla programów MFC.

  • ATLASSERT dla programów, które używają ATL.

  • Twierdzenia CRT dla programów, które używają biblioteki wykonawczej C.

  • ANSI dochodzić funkcja dla innych programów w języku C/C++.

Twierdzenia służy do połowu błędy logiczne, sprawdź wyniki operacji i przetestować warunków błędów, które powinny były przeładowywane.

W tym temacie

Jak działają potwierdzeń

Twierdzenia w buduje Debug i Release

Przy pomocy twierdzenia skutki uboczne

Twierdzenia CRT

Twierdzenia MFC

  • MFC ASSERT_VALID i CObject::AssertValid

  • Ograniczenia AssertValid

Przy pomocy twierdzenia

  • Błędy logiczne połowu

  • Weryfikacja wyników

  • Testowanie błędów

Jak działają potwierdzeń

Kiedy debuger zostanie zatrzymany z powodu MFC lub C, potwierdzenie biblioteki wykonawczej, jeśli źródło jest dostępna, debuger przejdzie następnie na punkt w pliku źródłowym, gdzie nastąpiło stwierdzenie.Pojawi się komunikat potwierdzenia w obu okna dane wyjściowe i Assertion Failed okno dialogowe.Można skopiować wiadomość potwierdzenia od produkcji okna do okna tekst, aby zapisać go w przyszłości.Produkcji okno może zawierać inne komunikaty błędów.Zbadać te komunikaty ostrożnie, ponieważ zapewniają one wskazówki do przyczyny niepowodzenia potwierdzenia.

Twierdzenia służy do wykrywania błędów w trakcie rozwoju.Zasadą jest Użyj jednego potwierdzenia na każde założenie.Na przykład jeśli można zakładać, że argument nie jest NULL, aby przetestować założeniu, że należy użyć potwierdzenia.

W tym temacie

Twierdzenia w buduje Debug i Release

Potwierdzenie instrukcji skompilować tylko wtedy, gdy _DEBUG jest zdefiniowana.W przeciwnym wypadku kompilator traktuje twierdzeń jako null instrukcji.W związku z tym, instrukcje potwierdzenia nakładać nie obciążenie lub wydajność kosztów w programie ostatecznego wydania i pozwalają uniknąć za pomocą #ifdef dyrektyw.

Przy pomocy twierdzenia skutki uboczne

Po dodaniu potwierdzeń w kodzie, upewnij się, że twierdzenia nie mają skutki uboczne.Na przykład, rozważmy następujące stwierdzenie, że modyfikuje nM wartość:

ASSERT(nM++ > 0); // Don't do this!

Ponieważ ASSERT w wersji tego programu, nie jest obliczane wyrażenie nM mają różne wartości w wersjach Debug i Release.Aby uniknąć tego problemu w MFC, można użyć Sprawdź makro, a nie ASSERT. VERIFYwyznacza wartość wyrażenia we wszystkich wersjach, ale nie sprawdza wynik w wersji wydania.

Należy zachować ostrożność zwłaszcza za pomocą wywołań funkcji w sprawozdaniu twierdzenie, ponieważ oceny funkcji może mieć nieoczekiwane działania niepożądane.

ASSERT ( myFnctn(0)==1 ) // unsafe if myFnctn has side effects
VERIFY ( myFnctn(0)==1 ) // safe

VERIFYwywołania myFnctn w wersji Debug i Release, czyli można korzystać.Jednak za pomocą VERIFY o wywołanie funkcji niepotrzebne w wersji wydania.

W tym temacie

Twierdzenia CRT

CRTDBG.Określa plik nagłówka H makra _ASSERT i _ASSERTE dla sprawdzenia potwierdzenia.

Makro

Wynik

_ASSERT

Jeśli określone wyrażenie zwróci wartość FAŁSZ, nazwę i wiersza numer akt _ASSERT.

_ASSERTE

Taki sam jak _ASSERT, plus reprezentację ciąg wyrażenia, które zostało potwierdzone.

_ASSERTEjest bardziej wydajne, ponieważ zgłasza go rzekoma wyrażenie, które okazały się być FAŁSZ.Może to być wystarczy, aby zidentyfikować problem bez odnoszące się do kodu źródłowego.Jednak wersja debugowania aplikacji będzie zawierać ciąg stała dla każdego wyrażenia potwierdzony za pomocą _ASSERTE.Jeśli używasz wielu _ASSERTE makr, te ciąg wyrażenia zajmują dużo pamięci.Jeśli okaże się to być problemem, użyj _ASSERT zapisać w pamięci.

Gdy _DEBUG jest zdefiniowana, _ASSERTE makro jest zdefiniowana w następujący sposób:

#define _ASSERTE(expr) \
   do { \
      if (!(expr) && (1 == _CrtDbgReport( \
         _CRT_ASSERT, __FILE__, __LINE__, #expr))) \
         _CrtDbgBreak(); \
   } while (0)

Jeśli rzekoma wyrażenie przyjmuje wartość FAŁSZ, _CrtDbgReport nazywa się zgłosić błąd potwierdzenia (Używanie okna dialogowego wiadomości domyślnie).Jeśli wybierzesz ponowić próbę w oknie dialogowym komunikatu, _CrtDbgReport zwraca wartość 1, i _CrtDbgBreak wywołuje narzędzie debugger za pośrednictwem DebugBreak.

Sprawdzanie uszkodzenie sterty

W poniższym przykładzie użyto _CrtCheckMemory Aby sprawdzić, czy uszkodzenie sterty:

_ASSERTE(_CrtCheckMemory());

Sprawdzanie poprawności wskaźnika

W poniższym przykładzie użyto _CrtIsValidPointer Aby sprawdzić zakres pamięci danego jest ważny do czytania lub pisania.

_ASSERTE(_CrtIsValidPointer( address, size, TRUE );

W poniższym przykładzie użyto _CrtIsValidHeapPointer do Sprawdź wskaźnik wskazuje pamięci w stercie lokalnych (sterty tworzone i zarządzane przez to wystąpienie biblioteki wykonawczej C — Biblioteka DLL może mieć własne wystąpienie biblioteki, a zatem własnej sterty, poza sterty aplikacji).Twierdzenie to nie przechwytuje tylko wartości null lub zdalne adresy, ale również wskaźniki do zmiennych statycznych, zmiennych stosu i innych nielokalne pamięci.

_ASSERTE(_CrtIsValidPointer( myData );

Sprawdzanie blok pamięci

W poniższym przykładzie użyto _CrtIsMemoryBlock czy blok pamięci znajduje się w stercie lokalnych, ma typ nieprawidłowy blok.

_ASSERTE(_CrtIsMemoryBlock (myData, size, &requestNumber, &filename, &linenumber));

W tym temacie

Twierdzenia MFC

Definiuje MFC ASSERT makro sprawdzania potwierdzenia.Niniejsza dyrektywa definiuje również MFC ASSERT_VALID i CObject::AssertValid metod kontrolowania wewnętrznego stanu CObject-pochodnych obiektu.

Jeśli argument MFC ASSERT makro ma wartość zero lub wartość FAŁSZ, makro przerywa wykonywanie program i powiadamia użytkownika; w przeciwnym razie kontynuuje wykonywanie.

Kiedy podanie zawiedzie, okno dialogowe wiadomości wyświetlana jest nazwa pliku źródłowego oraz numer wiersza twierdzenie.Jeżeli wybierz przycisk Ponów w oknie dialogowym pole, numer telefonu, aby AfxDebugBreak powoduje, że wykonanie do debugera.W tym momencie można zbadać stos wywołań i wykorzystać inne udogodnienia debugera do ustalenia, dlaczego potwierdzenie nie powiodło się.Jeśli włączono Debugowanie Just-in-timei debuger nie został jeszcze uruchomiony, okna dialogowego można uruchomić debugera.

Poniższy przykład pokazuje, jak używać ASSERT Aby sprawdzić wartość zwracana funkcji:

int x = SomeFunc(y);
ASSERT(x >= 0);   //  Assertion fails if x is negative

Można użyć ASSERT z IsKindOf funkcji typ sprawdzania argumentów funkcji:

ASSERT( pObject1->IsKindOf( RUNTIME_CLASS( CPerson ) ) );

ASSERT Makro powoduje brak kodu w wersji.Jeśli trzeba oszacować wyrażenia w wydanej wersji, należy użyć Sprawdź makro zamiast potwierdzenia.

MFC ASSERT_VALID i CObject::AssertValid

CObject::AssertValid metoda zapewnia wykonywania kontroli wewnętrznej stan obiektu.Chociaż nie jest wymagane Aby zastąpić AssertValid kiedy pochodzić od klasy CObject, można dokonać swojej klasy bardziej wiarygodne w ten sposób.AssertValidnależy wykonać potwierdzeń na wszystkie zmienne składowe obiektu, aby sprawdzić, czy zawierają prawidłowe wartości.Na przykład należy sprawdzić, czy zmienne składowe wskaźnik nie mają wartości NULL.

Poniższy przykład pokazuje sposób deklarowania AssertValid funkcji:

class CPerson : public CObject
{
protected:
    CString m_strName;
    float   m_salary;
public:
#ifdef _DEBUG
    // Override
    virtual void AssertValid() const;
#endif
    // ...
};

Kiedy można zastąpić AssertValid, wywołanie klasy podstawowej wersji AssertValid przed wykonaniem własne kontrole.Następnie należy użyć makra ASSERT Aby sprawdzić członków unikatowy do klasy pochodnej, jak pokazano poniżej:

#ifdef _DEBUG
void CPerson::AssertValid() const
{
    // Call inherited AssertValid first.
    CObject::AssertValid();

    // Check CPerson members...
    // Must have a name.
    ASSERT( !m_strName.IsEmpty());
    // Must have an income.
    ASSERT( m_salary > 0 );
}
#endif

Jeśli którykolwiek z swoje zmienne składowe są przechowywane obiekty, można użyć ASSERT_VALID makro, aby ich wewnętrzne ważność badania (jeśli ich klasy zastępują AssertValid).

Rozważmy na przykład klasy CMyData, które sklepy CObList w jednej z jego zmienne składowe.CObList Zmiennej, m_DataList, przechowywana kolekcja CPerson obiektów.Deklarację skróconą CMyData wygląda podobnie do następującej:

class CMyData : public CObject
{
    // Constructor and other members ...
    protected:
        CObList* m_pDataList;
    // Other declarations ...
    public:
#ifdef _DEBUG
        // Override:
        virtual void AssertValid( ) const;
#endif
    // And so on ...
};

AssertValid Zastępują w CMyData wygląda podobnie do następującej:

#ifdef _DEBUG
void CMyData::AssertValid( ) const
{
    // Call inherited AssertValid.
    CObject::AssertValid( );
    // Check validity of CMyData members.
    ASSERT_VALID( m_pDataList );
    // ...
}
#endif

CMyDataużywa AssertValid mechanizm, aby sprawdzić poprawność obiektów przechowywanych w jej członka danych.Przesłanianie AssertValid z CMyData wywołuje ASSERT_VALID makro dla własną zmienną m_pDataList.

Ważność badania nie zatrzymać na tym poziomie, ponieważ klasa CObList zastępuje również AssertValid.Ta zmiana odniesie wykonuje dodatkowe ważności badań przeprowadzanych na stan wewnętrzny listy.W efekcie ważności badania na CMyData obiektu prowadzi do ważności dodatkowe testy dla stanów wewnętrznych przechowywanej CObList obiektu list.

Z trochę więcej pracy, to można dodać testy poprawności dla CPerson obiektów również przechowywane na liście.Może pochodzić od klasy CPersonList z CObList i zastąpić AssertValid.W ręcznej zmiany, możesz wywołać CObject::AssertValid i następnie iteracyjne przeglądanie listy, wywołanie AssertValid na każdym CPerson obiektu przechowywane na liście.CPerson Się na początku tego tematu już klasa zastępuje AssertValid.

Jest to mechanizm potężny podczas konstruowania do debugowania.Gdy następnie zbudować dopuszczenia, mechanizm jest wyłączony automatycznie.

Ograniczenia AssertValid

Wyzwalane potwierdzenia wskazuje, że obiekt jest zdecydowanie zły i zatrzyma wykonywanie.Brak potwierdzenia wskazuje jednak tylko nie znaleziono problemów, że obiekt nie jest gwarantowane jest dobry.

W tym temacie

Przy pomocy twierdzenia

Błędy logiczne połowu

Podanie można ustawić pod warunkiem, że musi być spełnione zgodnie z logiką tego programu.Twierdzenie jest ignorowany, chyba że występuje błąd logiczny.

Załóżmy na przykład, symulują cząsteczek gazu w pojemniku i zmiennej numMols — łączną liczbę cząsteczek.Liczba ta nie może być mniejsza od zera, więc może zawierać instrukcję potwierdzenia MFC podobny do tego:

ASSERT(numMols >= 0);

Lub może zawierać potwierdzenie CRT podobny do tego:

_ASSERT(numMols >= 0);

Instrukcje te jeżeli nic program działa poprawnie.Jeśli błąd logiczny powoduje numMols być mniejsza od zera, Jednakże twierdzenie przerywa wykonywanie programu i wyświetla Błędy potwierdzenia — Okno dialogowe.

W tym temacie

Weryfikacja wyników

Twierdzenia są przydatne do testowania działania, którego wyniki nie są oczywiste z szybkie oględziny.

Rozważmy na przykład następujący kod, który aktualizuje zmiennej iMols na podstawie zawartości połączonej listy wskazywanego przez mols:

/* This code assumes that type has overloaded the != operator
 with const char * 
It also assumes that H2O is somewhere in that linked list. 
Otherwise we'll get an access violation... */
while (mols->type != "H2O")
{
 iMols += mols->num;
 mols = mols->next;
}
ASSERT(iMols<=numMols); // MFC version
_ASSERT(iMols<=numMols); // CRT version

Liczbę cząsteczek zliczonych przez iMols zawsze musi być mniejsza niż całkowita liczba cząsteczek, numMols.Oględziny pętli nie pokazuje, że to niekoniecznie będzie w przypadku, więc instrukcję potwierdzenia jest używany po pętli do testowania tego warunku.

W tym temacie

Błędy niezgodności z nieobsługiwanym

Twierdzenia można użyć do sprawdzenia warunków błędów w punkcie w kodzie gdzie wszelkie błędy powinny zostały obsłużone.W poniższym przykładzie graficzny rutynowych zwraca kod błędu lub wartość zero dla sukcesu.

myErr = myGraphRoutine(a, b);

/* Code to handle errors and
   reset myErr if successful */

ASSERT(!myErr); -- MFC version
_ASSERT(!myErr); -- CRT version

Jeśli kod obsługi błędów działa prawidłowo, powinno się obchodzić błędu i myErr reset do zera przed osiągnięciem twierdzenie.Jeśli myErr ma inną wartość, potwierdzenia kończy się niepowodzeniem, zatrzymanie programu i Błędy potwierdzenia — Okno dialogowe jest wyświetlany.

Instrukcje potwierdzenia nie są jednak substytut kod obsługi błędów.W poniższym przykładzie instrukcja potwierdzenia, która może prowadzić do problemów w kodzie ostatecznej wersji:

myErr = myGraphRoutine(a, b);

/* No Code to handle errors */

ASSERT(!myErr); // Don't do this!
_ASSERT(!myErr); // Don't do this, either!

Ten kod opiera się na sprawozdaniu potwierdzenia do obsługi warunek błędu.W rezultacie kod błędu zwrócony przez myGraphRoutine będzie nieobsługiwany kod wersji ostatecznej.

W tym temacie

Zobacz też

Informacje

Potwierdzenia w zarządzanym kodzie

Koncepcje

Zabezpieczenia debugera

Inne zasoby

Debugowanie kodu natywnego