Sprawdzanie wskaźnika NULL w C / C++ [zamknięte]

W ostatnim przeglądzie kodu, autor stara się wymusić, aby wszystkie NULL kontrole wskaźników były wykonywane w następujący sposób:

int * some_ptr;
// ...
if (some_ptr == NULL)
{
    // Handle null-pointer error
}
else
{
    // Proceed
}

Zamiast

int * some_ptr;
// ...
if (some_ptr)
{
    // Proceed
}
else
{
    // Handle null-pointer error
}

Zgadzam się, że jego sposób jest nieco bardziej jasny w tym sensie, że wyraźnie mówi "upewnij się, że ten wskaźnik nie jest NULL" , ale chciałbym temu przeciwdziałać, mówiąc, że każdy, kto pracuje nad tym kodem, zrozumie, że użycie zmiennej wskaźnika w if jest niejawnym sprawdzaniem NULL. Również Ja feel druga metoda ma mniejsze szanse na wprowadzenie błędu ilk:

if (some_ptr = NULL)

Co jest po prostu absolutnym bólem, aby znaleźć i debugować.

Którą drogę wolisz i dlaczego?

Author: Peter Mortensen, 2010-09-30

15 answers

Z mojego doświadczenia wynika, że preferowane są testy formy if (ptr) LUB if (!ptr). Nie zależą one od definicji symbolu NULL. Nie ujawniają możliwości przypadkowego przydziału. I są jasne i zwięzłe.

Edit: Jak wskazuje SoapBox w komentarzu, są one kompatybilne z klasami C++, takimi jak auto_ptr, które są obiektami pełniącymi funkcję wskaźników i które zapewniają konwersję do bool, aby włączyć dokładnie ten idiom. Dla tych obiektów jawny porównanie z NULL musiałoby wywoływać konwersję na wskaźnik, która może mieć inne semantyczne skutki uboczne lub być droższa niż prosta kontrola istnienia, którą implikuje konwersja bool.

Preferuję kod, który mówi, co oznacza bez zbędnego tekstu. if (ptr != NULL) ma to samo znaczenie co if (ptr), ale kosztem redundantnej specyficzności. Następną logiczną rzeczą jest napisanie if ((ptr != NULL) == TRUE) i w ten sposób leży szaleństwo. Języka C jest jasne, że boolean testowany przez if, while lub podobne ma specyficzne znaczenie niezerowa wartość jest prawdziwa, a zero jest fałszywe. Redundancja nie czyni tego jaśniejszym.

 165
Author: RBerteig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-30 01:10:26

if (foo) jest wystarczająco jasne. Użyj go.

 49
Author: wilx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-29 20:44:53

Zacznę od tego: konsekwencja jest królem, decyzja jest mniej ważna niż spójność w bazie kodu.

W C++

NULL jest zdefiniowany jako 0 lub 0L w C++.

Jeśli czytałeś język programowania C++ Bjarne Stroustrup sugeruje użycie 0 jawnie, aby uniknąć makra NULL podczas wykonywania zadania, nie jestem pewien, czy zrobił to samo z porównaniami, minęło trochę czasu, odkąd przeczytałem książkę, myślę, że po prostu zrobił if(some_ptr) bez wyraźne porównanie, ale jestem w tym zamazany.

Powodem tego jest to, że makro NULL jest zwodnicze (jak prawie wszystkie makra). Unikanie makr jest jednym z ogólnych wytycznych w C++. Z drugiej strony, 0 wygląda jak liczba całkowita i nie jest porównywana lub przypisywana do wskaźników. Osobiście mógłbym pójść w obie strony, ale zazwyczaj pomijam jednoznaczne porównanie (choć niektórzy nie lubią to pewnie dlatego i tak masz współpracownika sugerującego zmianę).

Niezależnie od osobistych uczuć jest to w dużej mierze wybór najmniejszego zła, ponieważ nie ma jednej właściwej metody.

Jest to jasny i powszechny idiom i wolę go, nie ma szans na przypadkowe przypisanie wartości podczas porównania i czyta się wyraźnie:

if(some_ptr){;}

Jest to jasne, jeśli wiesz, że some_ptr jest typem wskaźnika, ale może również wyglądać jak porównanie liczb całkowitych:

if(some_ptr != 0){;}

Jest to jasne, w zwykłych przypadkach ma to sens... Ale to nieszczelna abstrakcja, NULL jest w rzeczywistości 0 dosłowna i może łatwo zostać źle użyta:

if(some_ptr != NULL){;}

C++0x ma nullptr, który jest teraz preferowaną metodą, ponieważ jest jawny i dokładny, po prostu uważaj na przypadkowe przypisanie:

if(some_ptr != nullptr){;}

Dopóki nie będziesz w stanie przenieść się do C++0x, argumentowałbym, że to strata czasu martwiąc się, którą z tych metod używasz, wszystkie są niewystarczające dlatego wynaleziono nullptr (wraz z ogólnymi problemami programistycznymi, które pojawiły się z doskonałym przekierowaniem.) Najważniejsze jest zachowanie spójności.

W C

C to inna bestia.

W C NULL może być zdefiniowane jako 0 lub jako ((void *)0), C99 pozwala na implementację zdefiniowanych stałych wskaźnika null. Sprowadza się to więc do definicji implementacji NULL i będziesz musiał sprawdzić ją w swojej bibliotece standardowej.

Makra to bardzo często i ogólnie są one często używane, aby nadrobić braki w ogólnym wsparciu programistycznym w języku i innych rzeczach, jak również. Język jest znacznie prostszy i bardziej powszechny.

Z tej perspektywy prawdopodobnie zalecałbym użycie definicji makra NULL W C.

 20
Author: M2tM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-30 21:33:19

Używam if (ptr), ale nie warto się o to spierać.

Lubię swój sposób, ponieważ jest zwięzły, choć inni mówią, że ułatwia czytanie i jest bardziej wyraźny. Widzę skąd pochodzą, po prostu nie zgadzam się, że dodatkowe rzeczy ułatwiają sprawę. (Nienawidzę makro, więc jestem stronniczy.) Zależy od Ciebie.

Nie zgadzam się z Twoim argumentem. Jeśli nie otrzymujesz ostrzeżeń dla zadań warunkowych, musisz zwiększyć poziom ostrzeżeń. To proste. (I z miłości do wszystko, co jest dobre, nie zmieniaj ich.)

Uwaga W C++0x możemy zrobić if (ptr == nullptr), co dla mnie robi ładniej. (Ponownie nienawidzę makro. Ale to miłe.) Nadal robię if (ptr), tylko dlatego, że jestem do tego przyzwyczajony.

 18
Author: GManNickG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-29 20:46:42

Szczerze mówiąc, nie rozumiem, dlaczego to ma znaczenie. Każda z nich jest dość jasna i każdy umiarkowanie doświadczony w C lub c++ powinien zrozumieć oba. Jeden komentarz:

Jeśli planujesz rozpoznać błąd i nie kontynuować wykonywania funkcji (np. wyrzucisz wyjątek lub natychmiast zwrócisz kod błędu), powinieneś zrobić z niego klauzulę ochronną:

int f(void* p)
{
    if (!p) { return -1; }

    // p is not null
    return 0;
}

W ten sposób unikasz "kodu strzałek."

 9
Author: James McNellis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-29 21:04:05

Właściwie, używam obu wariantów.

Są sytuacje, w których najpierw sprawdzasz Ważność wskaźnika, a jeśli jest NULL, po prostu zwracasz / kończysz funkcję. (Wiem, że może to prowadzić do dyskusji "czy funkcja powinna mieć tylko jeden punkt wyjścia")

Przez większość czasu sprawdzasz wskaźnik, a następnie robisz, co chcesz, a następnie rozwiązujesz problem błędu. Rezultatem może być brzydki x-krotnie wcięty kod z wieloma if ' ami.

 4
Author: dwo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-29 20:46:47

Osobiście zawsze używałem if (ptr == NULL), ponieważ to czyni moje intencje wyraźnymi, ale w tym momencie jest to tylko nawyk.

Użycie = zamiast == zostanie przechwycone przez kompetentny kompilator z poprawnymi ustawieniami ostrzegawczymi.

Ważne jest, aby wybrać spójny styl dla swojej grupy i trzymać się go. Bez względu na to, w którą stronę pójdziesz, w końcu przyzwyczaisz się do tego, a utrata tarcia podczas pracy w cudzym kodzie będzie mile widziana.

 4
Author: Mark Ransom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-29 21:03:55

Jeszcze jeden punkt na korzyść praktyki foo == NULL : Jeśli foo jest, powiedzmy, int * lub bool *, to sprawdzenie if (foo) może być przypadkowo zinterpretowane przez czytelnika jako testowanie wartości punktu, tzn. jako if (*foo). Porównanie NULL jest przypomnieniem, że mówimy o wskaźniku.

Ale przypuszczam, że dobra konwencja nazewnictwa sprawia, że ten argument jest dyskusyjny.

 4
Author: Daniel Hershcovich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-10 16:41:58

Język programowania C (K & R) wymagałoby sprawdzenia null = = ptr, aby uniknąć przypadkowego przyporządkowania.

 4
Author: Derek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-30 14:48:34

Jeśli styl i format będą częścią twoich recenzji, powinien być uzgodniony przewodnik po stylach, z którym możesz się zmierzyć. Jeśli taki istnieje, zrób to, co mówi przewodnik stylu. Jeśli nie ma takiego, szczegóły takie jak ten powinny być pozostawione tak, jak są napisane. To strata czasu i energii, i odwraca uwagę od tego, co recenzje kodu naprawdę powinny być odkrywania. Poważnie, bez przewodnika po stylach naciskałbym, aby z zasady nie zmieniać kodu w ten sposób, nawet jeśli nie używa on konwencji I wolę.

I nie żeby to miało znaczenie, ale moje osobiste preferencje są if (ptr). Znaczenie jest dla mnie bardziej oczywiste niż if (ptr == NULL).

Może próbuje powiedzieć, że lepiej jest poradzić sobie z błędami przed Szczęśliwą ścieżką? W takim razie nadal nie zgadzam się z recenzentem. Nie wiem, czy jest na to przyjęta konwencja, ale moim zdaniem najbardziej "normalny" stan powinien być na pierwszym miejscu w każdym oświadczeniu if. W ten sposób mam mniej kopania do zrobienia, aby dowiedzieć się na czym polega funkcja i jak działa.

Wyjątkiem jest to, czy błąd powoduje, że rezygnuję z funkcji lub mogę się z niej wyleczyć przed przejściem dalej. W takich przypadkach najpierw zajmuję się błędem:

if (error_condition)
  bail_or_fix();
  return if not fixed;

// If I'm still here, I'm on the happy path
/ Align = "left" / Ale jeśli nie mogę wrócić na szczęśliwą ścieżkę, obsługując go z przodu, to powinien być obsługiwany po głównym przypadku, ponieważ sprawia, że kod bardziej to zrozumiałe. Moim zdaniem.

Ale jeśli nie jest to przewodnik po stylu, to tylko moja opinia, a twoja opinia jest równie ważna. Albo standaryzować, albo nie. nie pozwól recenzentowi pseudo-standaryzować tylko dlatego, że ma opinię.

 3
Author: Darryl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-29 21:28:42

Myślę, że to jest całkiem jasne:

if( !some_ptr )
{
  // handle null-pointer error
}
else
{
  // proceed
}

Odczytaj jako " Jeśli nie ma wskaźnika ..."

Dodatkowo jest zwięzły i nie ma niebezpieczeństwa przypadkowych przydziałów.

 1
Author: sth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-29 20:47:15

Jest to jedna z podstaw obu języków, które wskaźniki oceniają do typu i wartości, które mogą być używane jako wyrażenie sterujące, bool w C++ i int W C. Wystarczy go użyć.

 1
Author: Jens Gustedt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-29 21:01:41

Jestem wielkim fanem tego, że C / C++ nie sprawdza typów w Warunkach logicznych w if, for i while wypowiedzi. Zawsze używam:

if (ptr)

if (!ptr)

Nawet na liczbach całkowitych lub innych typach, które konwertują na bool:

while(i--)
{
    // Something to do i times
}

while(cin >> a >> b)
{
    // Do something while you've input
}

Kodowanie w tym stylu jest dla mnie bardziej czytelne i wyraźniejsze. To tylko moja osobista opinia.

Ostatnio, pracując na mikrokontrolerze OKI 431, zauważyłem, że:

unsigned char chx;

if (chx) // ...

Jest bardziej wydajny niż

if (chx == 1) // ...

Ponieważ w później kompilator musi porównać wartość chx do 1. Gdzie chx to po prostu flaga prawda/fałsz.

 1
Author: Donotalo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-30 17:21:05

Większość kompilatorów, których używałem, będzie przynajmniej ostrzegać o przypisaniu if bez dalszego cukru składniowego, więc nie kupuję tego argumentu. To powiedziawszy, używałem zarówno profesjonalnie, jak i nie mam żadnych preferencji. == NULL jest zdecydowanie jaśniejszy, choć moim zdaniem.

 1
Author: Michael Dorgan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-04 18:30:18
  • Pointers are not booleans
  • Współczesne kompilatory C / C++ emitują ostrzeżenie, gdy piszesz if (foo = bar) przez przypadek.

Dlatego wolę

if (foo == NULL)
{
    // null case
}
else
{
    // non null case
}

Lub

if (foo != NULL)
{
    // non null case
}
else
{
    // null case
}

Jednakże, gdybym pisał zestaw wytycznych stylu, nie umieszczałbym w nim takich rzeczy, tylko takie:

Upewnij się, że nie sprawdzasz wskaźnika.

 0
Author: JeremyP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-30 10:01:02