Megosztás a következőn keresztül:


C/C++ állítások

Az állítási utasítás olyan feltételt határoz meg, amely a program egy pontján való igaznak számít. Ha ez a feltétel nem igaz, az állítás meghiúsul, a program végrehajtása megszakad, és megjelenik a Helyességi sikertelenség párbeszédpanel .

A Visual Studio az alábbi szerkezeteken alapuló C++ állítási utasításokat támogatja:

  • MFC-állítások MFC-programokhoz.

  • ATLASSERT atl-t használó programokhoz.

  • CRT-állítások a C futásidejű kódtárat használó programokhoz.

  • Az ANSI-érvényesítési függvény más C/C++ programokhoz.

    Az állításokkal logikai hibákat foghat el, ellenőrizheti egy művelet eredményeit, és tesztelheti a hibafeltételeket, amelyeket kezelni kellett volna.

Ebben a témakörben

Az állítások működése

Állítások hibakeresési és kiadási buildekben

Az állítások használatának mellékhatásai

CRT-állítások

MFC-állítások

Az állítások működése

Ha a hibakereső egy MFC vagy C futásidejű kódtár-állítás miatt leáll, akkor ha a forrás elérhető, a hibakereső a forrásfájl azon pontjára navigál, ahol az állítás történt. Az érvényesítési üzenet a Kimenet ablakban és az Igény nem sikerült párbeszédpanelen is megjelenik. A helyességi üzenetet a Kimenet ablakból átmásolhatja egy szövegablakba, ha későbbi használatra szeretné menteni. A Kimeneti ablak más hibaüzeneteket is tartalmazhat. Gondosan vizsgálja meg ezeket az üzeneteket, mert nyomokat adnak az állítási hiba okához.

A fejlesztés során hibák észleléséhez használjon állításokat. Általában minden feltételezéshez használjon egy állítást. Ha például azt feltételezi, hogy egy argumentum nem NULL, egy állítás használatával tesztelje ezt a feltételezést.

Ebben a témakörben

Állítások hibakeresési és kiadási buildekben

A helyességi utasítások csak akkor állnak össze, ha _DEBUG definiálva van. Ellenkező esetben a fordító üres utasításként kezeli az állításokat. Ezért az állítási utasítások nem rónak többletterhelést vagy teljesítményköltséget a végleges kiadási programra, és lehetővé teszik, hogy elkerülhetjük a #ifdef direktívák használatát.

Az állítások használatának mellékhatásai

Ha állításokat ad hozzá a kódhoz, győződjön meg arról, hogy az állításoknak nincsenek mellékhatásai. Vegyük például az alábbi állítást, amely módosítja az nM értéket:

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

Mivel a ASSERT kifejezés nem a program kiadási verziójában van kiértékelve, nM a hibakeresési és kiadási verziókban eltérő értékek jelennek meg. A probléma elkerülése érdekében az MFC-ben a VERIFY makrót használhatja ahelyett ASSERT, hogy . VERIFY kiértékeli a kifejezést az összes verzióban, de nem ellenőrzi az eredményt a kiadási verzióban.

Különösen ügyeljen arra, hogy függvényhívásokat használjon az állítási utasításokban, mert a függvények kiértékelése váratlan mellékhatásokat okozhat.

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

VERIFY mind a Debug, mind a Release verzióban meghívja myFnctn, ezért elfogadható a használata. Azonban, a VERIFY használata a kiadási verzióban szükségtelen függvényhívásból származó többletterhet okoz.

Ebben a témakörben

CRT-állítások

A CRTDBG.H fejlécfájl határozza meg a helyességi ellenőrzéshez szükséges makrókat és _ASSERT makrókat._ASSERTE

Macro Result
_ASSERT Ha a megadott kifejezés értéke HAMIS, akkor a fájl neve és sorszáma megjelenik._ASSERT
_ASSERTE Ugyanaz, mint _ASSERT, valamint az érvényesített kifejezés szövegábrázolása.

_ASSERTE hatékonyabb, mert beszámol azon állított kifejezésről, amely hamisnak bizonyult. Ez elegendő lehet a probléma azonosításához a forráskódra való hivatkozás nélkül. Az alkalmazás Debug verziója azonban egy szövegkonstansot fog tartalmazni minden olyan kifejezéshez, amelyet kijelentettünk _ASSERTE használatával. Ha sok _ASSERTE makrót használ, ezek a sztringkifejezések jelentős mennyiségű memóriát vesznek igénybe. Ha ez problémának bizonyul, használja _ASSERT a memória mentéséhez.

Ha _DEBUG definiálva van, a makró a _ASSERTE következőképpen van definiálva:

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

Ha az érvényesített kifejezés HAMIS értékre van kiértékelve, a rendszer meghívja _CrtDbgReport az állítási hiba jelentésére (alapértelmezés szerint egy üzenet párbeszédpanel használatával). Ha az Üzenet párbeszédpanelen az Újrapróbálkozás lehetőséget választja, a c1 /> 1-et ad vissza, és a _CrtDbgBreak meghívja a hibakeresőt a DebugBreak-en keresztül.

Ha ideiglenesen le kell tiltania az összes állítást, használja _CtrSetReportMode.

A halom sérülésének ellenőrzése

Az alábbi példa a _CrtCheckMemory-t használja a halom sérülésének ellenőrzésére:

_ASSERTE(_CrtCheckMemory());

Mutató érvényességének ellenőrzése

Az alábbi példa _CrtIsValidPointer használatával ellenőrzi, hogy egy adott memóriatartomány érvényes-e olvasásra vagy írásra.

_ASSERTE(_CrtIsValidPointer( address, size, TRUE );

Az alábbi példa _CrtIsValidHeapPointer használ annak ellenőrzésére, hogy egy mutató a helyi halomban lévő memóriára mutat-e (a C futásidejű kódtár ezen példánya által létrehozott és felügyelt halom – a DLL-nek saját példánya lehet a tárból, és így saját halomból, az alkalmazás halomtárán kívül). Ez az állítás nem csak a null vagy a határon kívüli címeket rögzíti, hanem statikus változókra, veremváltozókra és egyéb nem lokális memóriára mutató mutatókat is.

_ASSERTE(_CrtIsValidHeapPointer( myData );

Memóriablokk ellenőrzése

Az alábbi példa _CrtIsMemoryBlock használatával ellenőrzi, hogy egy memóriablokk a helyi halomban van-e, és érvényes blokktípussal rendelkezik-e.

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

Ebben a témakörben

MFC-állítások

Az MFC határozza meg az ASSERT makrót a kijelentés-ellenőrzéshez. Meghatározza a MFC ASSERT_VALID származtatott objektumok belső állapotának CObject::AssertValidellenőrzésére szolgáló módszereket és CObject módszereket is.

Ha az MFC-makró ASSERT argumentuma nullára vagy hamisra értékel, a makró leállítja a program végrehajtását, és értesíti a felhasználót; ellenkező esetben a végrehajtás folytatódik.

Ha egy állítás meghiúsul, egy üzenet párbeszédpanelen megjelenik a forrásfájl neve és az állítás sorszáma. Ha a párbeszédpanelen az Újrapróbálkozás lehetőséget választja, az AfxDebugBreak hívása miatt a végrehajtás megszakad a hibakeresőhöz. Ezen a ponton megvizsgálhatja a hívási vermet, és más hibakereső létesítmények használatával megállapíthatja, hogy az állítás miért nem sikerült. Ha engedélyezte a just-in-time hibakeresést, és a hibakereső még nem futott, a párbeszédpanel elindíthatja a hibakeresőt.

Az alábbi példa bemutatja, hogyan ellenőrizheti ASSERT egy függvény visszatérési értékét:

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

A IsKindOf függvényt az ASSERT-tel használhatja, hogy típusellenőrzést végezzen a függvényargumentumok között.

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

A ASSERT makró nem hoz létre kódot a Kiadás verzióban. Ha kiértékelni kell a kifejezést a kiadás verzióban, használja a VERIFY makrót az ASSERT helyett.

MFC ASSERT_VALID és CObject::AssertValid

A CObject::AssertValid metódus futásidejű ellenőrzéseket biztosít egy objektum belső állapotáról. Bár nem kötelező felülírnia a CObject osztály származékát, ezzel a módszerrel megbízhatóbbá teheti az osztályt. AssertValid az objektum összes tagváltozóján ellenőrzéseket kell végrehajtani, hogy meggyőződjünk arról, hogy érvényes értékeket tartalmaznak. Ellenőriznie kell például, hogy a mutatótag változói nem NULL értékűek-e.

Az alábbi példa bemutatja, hogyan deklarálhat függvényt AssertValid :

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

A felülbíráláskor AssertValidhívja meg az alaposztály verzióját AssertValid , mielőtt saját ellenőrzéseket végez. Ezután az ASSERT makróval ellenőrizze a származtatott osztályhoz tartozó egyedi tagokat az itt látható módon:

#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

Ha bármelyik tagváltozója objektumokat tárol, a ASSERT_VALID makrót használhatja az objektumok belső érvényességének tesztelésére (feltéve, hogy az osztályaik felülírják a AssertValid metódust).

Vegyük például azt az osztályt CMyData, amely egy CObList-et tárol az egyik tagváltozójában. A CObList változó m_DataListobjektumgyűjteményt CPerson tárol. A következőképpen néz ki egy rövidített deklaráció CMyData :

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 ...
};

A AssertValid felülbírálás a CMyData következőképpen néz ki:

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

CMyData a mechanizmus használatával AssertValid teszteli az adatelemben tárolt objektumok érvényességét. A CMyData felülírása a ASSERT_VALID makró meghívását követeli meg a saját m_pDataList tagváltozójához.

Az érvényességi tesztelés ezen a szinten nem áll le, mert az osztály CObList felülbírálja AssertValidis. Ez a felülbírálás további érvényességi teszteket végez a lista belső állapotán. Így egy CMyData objektum érvényességi tesztje további érvényességi teszteket eredményez a tárolt CObList listaobjektum belső állapotára vonatkozóan.

Néhány további munkával érvényességi teszteket is hozzáadhat a CPerson listában tárolt objektumokhoz. Származtathat egy CPersonList osztályt a CObList-ből, és felülbírálhatja a AssertValid-t. A felülbírálás során meghívja CObject::AssertValid, majd végigiterál a listán, és meghívja a AssertValid metódust a listában tárolt minden egyes CPerson objektumra. A CPerson témakör elején látható osztály már felülírja AssertValid.

Ez egy hatékony mechanizmus, ha hibakereséshez épít. Amikor később kiadásra készül, a rendszer automatikusan kikapcsolja a mechanizmust.

Az AssertValid korlátozásai

Az aktivált állítás azt jelzi, hogy az objektum határozottan rossz, és a végrehajtás leáll. Az állítás hiánya azonban csak azt jelzi, hogy nem található probléma, de az objektum nem garantáltan jó.

Ebben a témakörben

Állítások használata

Logikai hibák észlelése

Beállíthat olyan feltételre vonatkozó állítást, amely a program logikájának megfelelően igaznak kell lennie. Az állításnak nincs hatása, hacsak nem fordul elő logikai hiba.

Tegyük fel például, hogy gázmolekulákat szimulál egy tárolóban, és a változó numMols a molekulák teljes számát jelöli. Ez a szám nem lehet kisebb nullánál, ezért az alábbihoz hasonló MFC-utasítást is tartalmazhat:

ASSERT(numMols >= 0);

Vagy a következőhöz hasonló CRT-állítást is tartalmazhat:

_ASSERT(numMols >= 0);

Ezek az utasítások nem tesznek semmit, ha a program megfelelően működik. Ha azonban egy logikai hiba nullánál kisebb hibát okoz numMols , az állítás leállítja a program végrehajtását, és megjeleníti a Hibás állítás párbeszédpanelt.

Ebben a témakörben

Eredmények ellenőrzése

Az állítások értékesek olyan tesztelési műveletekhez, amelyek eredményei nem egyértelműek egy gyors vizualizációs vizsgálatból.

Vegyük például a következő kódot, amely a változót iMols a hivatkozott lista molstartalma alapján frissíti:

/* 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

A megszámlált iMols molekulák számának mindig kisebbnek vagy egyenlőnek kell lennie a molekulák teljes számánál, numMols. A hurok vizuális vizsgálata nem mutatja, hogy ez feltétlenül így lesz, ezért a ciklus után egy helyességi utasítást használnak az adott feltétel teszteléséhez.

Ebben a témakörben

Nem kezelt hibák keresése

Állításokkal tesztelheti a hibahelyzeteket a kód azon pontján, ahol minden hibát kezelni kellett volna. Az alábbi példában egy grafikus rutin egy hibakódot vagy nullát ad vissza a sikerhez.

myErr = myGraphRoutine(a, b);

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

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

Ha a hibakezelő kód megfelelően működik, a hibát kezelni kell, és myErr nullára kell állítani az állítás elérése előtt. Ha a myErr más értéket vesz fel, az állítás meghiúsul, a program leáll, és megjelenik az Állítás Sikertelen Párbeszédpanel.

A helyességi utasítások azonban nem helyettesítik a hibakezelési kódot. Az alábbi példa egy állítási utasítást mutat be, amely problémákhoz vezethet a végleges kiadási kódban:

myErr = myGraphRoutine(a, b);

/* No Code to handle errors */

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

Ez a kód a helyességi utasításra támaszkodik a hibafeltétel kezeléséhez. Ennek eredményeképpen a visszaadott myGraphRoutine hibakódok nem lesznek kezelve a végleges kiadási kódban.

Ebben a témakörben