Table of contents

  1. Używanie makra assert
    1. Po co?
    2. Co to?
    3. Jak?
    4. Gdzie?
    5. Błędne błędy
    6. Gdy już pada
    7. Podsumowując
    8. PHP

Po co?

Najgorsze w programach są błędy, które nie powodują jego powieszenia, a najwyżej niezamierzone działanie. Czasem długo można szukać błędu. Nie wiadomo gdzie się problem zaczyna, itd.
Tego typu błędy najlepiej wyłapać jak najwcześniej. Jak? Robiąc samosprawdzający się program. Jak? Makrami assert()

Co to?

(z ang. upewnić się)

Makro assert() sprawdza podane mu wyrazenie czy jest różne od zera (prawdziwe). Jeśli nie jest — program zostanie zatrzymany, podane zostanie miejsce błędu i wyrażenie, które “nawaliło”.

Jak?

#include <assert.h>

W finalnej wersji programu zdefiniuj NDEBUG dzięki czemu wszystkie makra assert znikną z programu. Można to zrobić przez switch kompilatora (w gcc to jest -DNDEBUG) albo poprostu przez #define NDEBUG

Gdzie?

Wszędzie! Makra assert są usuwane z finalnej wersji programu, więc nic nie szkodzi ich używać w przeogromnych ilościach.

funkcja(void *dane, int dlugosc)
{
assert(dane); // sprawdzi czy wskaznik nie jest NULL (po co komu system z ochroną pamięci? ;)
assert(dlugosc >= 0); // dobrze jest wylapywac kazdy bezsens, ktory moglby powstac w programie
}
select(bla)
{
default:
assert(!“kod nie powinien tu dojsc”); // odpowiednik assert(0).
// program zostanie zawsze zatrzymany. dodatkowa sztuczka polega na tym, ze bedzie mozna odczytac komunikat.
}

Błędne błędy

Nie wstawiaj do makra assert żadnych wyrażeń mających efekt uboczny! np:

assert(a = b+1);
assert(c = d);
assert(e++);

złe. Obliczenie tego wyrażenia zmieni coś w programie. A wyrażenia wewnątrz makra assert() nie są obliczane w finalnej wersji programu.

Natomiast:

assert(a > b+1);
assert(c == d);
assert(e);

OK.

Trzeba o tym pamiętać również gdy używa się funkcji wewnątrz makra:

assert(strlen(foo)) — dobrze. niezależnie czy się wywoła funkcję strlen, czy nie, to program będzie zachowywał się tak samo.
assert(fopen("plik","r")) — źle. wersja testowa programu będzie próbowała otworzyć plik, a finalna nie.

Gdy już pada

Gdy makro assert natrafi na błąd to zatrzymuje program. Żeby program przed “katapultowaniem się” zwolnił pamięć trzeba napisać odpowiednią funkcję i podpiąć ją pod atexit().

Jeśli takie zachowanie jest zbyt drastyczne można napisać własną wersję makra, która np. zapyta czy kontynuować program.

Podsumowując

Warto kod gęsto naszpikować assert()ami, które wyłapią anomalie najczęściej zanim program będzie miał okazję coś popsuć.

PHP

Tak na boku dodam, że PHP ma funkcję assert(). Od odpowiednika w C różni się tym, że całe sprawdzane wyrażenie należy umieścić w (pojedynczym) cudzysłowiu.

assert('$dwa + $dwa == $cztery');