W ostatnim przeglądzie kodu współtwórca próbuje wymusić, aby wszystkie NULL
sprawdzenia 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 przejrzysty w tym sensie, że wyraźnie mówi „Upewnij się, że ten wskaźnik nie ma wartości NULL”, ale chciałbym temu przeciwdziałać, mówiąc, że każdy, kto pracuje nad tym kodem, zrozumiałby, że użycie zmiennej wskaźnika w if
instrukcja niejawnie sprawdzaNULL
. Uważam również, że druga metoda ma mniejsze szanse na wprowadzenie błędu podobnego:
if (some_ptr = NULL)
co jest absolutnym trudem do znalezienia i debugowania.
Który sposób wolisz i dlaczego?
c++
c
if-statement
null
coding-style
Bryan Marble
źródło
źródło
Odpowiedzi:
Z mojego doświadczenia wynika, że preferowane są testy formy
if (ptr)
lubif (!ptr)
. Nie zależą od definicji symboluNULL
. Nie stwarzają okazji do przypadkowego zadania. Są jasne i zwięzłe.Edycja: jak SoapBox wskazuje w komentarzu, są one kompatybilne z klasami C ++, takimi jak
auto_ptr
obiekty, które działają jako wskaźniki i które zapewniają konwersję,bool
aby włączyć dokładnie ten idiom. W przypadku tych obiektów jawne porównanieNULL
musiałoby wywołać konwersję do wskaźnika, co może mieć inne semantyczne skutki uboczne lub być droższe niż proste sprawdzenie istnienia, którebool
implikuje konwersja.Preferuję kod, który mówi, co to znaczy, bez zbędnego tekstu.
if (ptr != NULL)
ma to samo znaczenie,if (ptr)
ale kosztem zbędnej specyfiki. Następną logiczną rzeczą jest pisanieif ((ptr != NULL) == TRUE)
i na tym polega szaleństwo. Język C jest jasne, że logiczna przetestowany przezif
,while
lub jak ma szczególne znaczenie z niezerową wartością jest prawda i zero jest fałszywe. Nadmiarowość nie czyni tego jaśniejszym.źródło
int y = *x; if (!x) {...}
której optymalizator może stwierdzić, że skoro*x
byłoby niezdefiniowane, jeślix
ma wartość NULL, nie może mieć wartości NULL, a zatem!x
musi mieć wartość FALSE. Wyrażenie nie!ptr
jest niezdefiniowanym zachowaniem. W tym przykładzie, jeśli test został wykonany przed jakimkolwiek użyciem , optymalizator pomyliłby się, eliminując test.*x
if (foo)
jest wystarczająco jasne. Użyj tego.źródło
Zacznę od tego: spójność jest królem, decyzja jest mniej ważna niż spójność w bazie kodu.
W C ++
NULL jest definiowane jako 0 lub 0L w C ++.
Jeśli przeczytałeś Język programowania C ++ Bjarne Stroustrup sugeruje użycie
0
jawnego unikaniaNULL
makra podczas wykonywania przypisań , nie jestem pewien, czy zrobił to samo z porównaniami, minęło trochę czasu, odkąd przeczytałem książkę, myślę, że właśnie to zrobiłif(some_ptr)
bez wyraźnego porównania, ale jestem niejasny.Powodem tego jest to, że
NULL
makro jest zwodnicze (jak prawie wszystkie makra), w rzeczywistości jest0
dosłowne, a nie jest unikalnym typem, jak sugeruje nazwa. Unikanie makr to jedna z ogólnych wskazówek w C ++. Z drugiej strony0
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 wyraźne porównanie (chociaż niektórym to się nie podoba, dlatego prawdopodobnie masz współpracownika sugerującego zmianę).Niezależnie od osobistych odczuć jest to w dużej mierze wybór najmniejszego zła, ponieważ nie ma jednej właściwej metody.
To jest klarowny i powszechny idiom i wolę taki, nie ma szans przypadkowego przypisania wartości podczas porównania i czyta się wyraźnie:
Jest to jasne, jeśli wiesz, że
some_ptr
jest to typ wskaźnika, ale może również wyglądać jak porównanie liczb całkowitych:Jest to jasne, w typowych przypadkach ma to sens ... Ale jest to nieszczelna abstrakcja, w
NULL
rzeczywistości jest0
dosłowna i może łatwo zostać niewłaściwie wykorzystana:C ++ 0x ma nullptr, który jest teraz preferowaną metodą, ponieważ jest wyraźny i dokładny, po prostu uważaj na przypadkowe przypisanie:
Dopóki nie będziesz w stanie przejść na C ++ 0x, uważałbym, że to strata czasu na martwienie się o to, której z tych metod używasz, wszystkie są niewystarczające, dlatego wynaleziono nullptr (razem z ogólnymi problemami programistycznymi, które doprowadziły do idealnego przekazywania .) Najważniejsze jest zachowanie spójności.
W C
C to inna bestia.
W C NULL można zdefiniować jako 0 lub jako ((void *) 0), C99 pozwala na implementację zdefiniowanych zerowych stałych wskaźnika. Tak więc sprowadza się to do definicji NULL zdefiniowanej przez implementację i będziesz musiał sprawdzić to w swojej standardowej bibliotece.
Makra są bardzo powszechne i na ogół są często używane, aby nadrobić braki w ogólnej obsłudze programowania w języku i nie tylko. Język jest znacznie prostszy i bardziej powszechne jest poleganie na preprocesorze.
Z tego punktu widzenia prawdopodobnie zalecałbym użycie
NULL
definicji makra w C.źródło
0
w C ++, to ma sens w katalogu C:(void *)0
.0
jest lepsze niżNULL
w C ++, ponieważ błędy typu mogą być PITA.NULL
tak wynosi zero.#define NULL ((void *)0)
odlinux/stddef.h
NULL
musi wynosić zero.Używam
if (ptr)
, ale zupełnie nie warto się o to spierać.Podoba mi się mój sposób, ponieważ jest zwięzły, chociaż inni mówią,
== NULL
że jest łatwiejszy do odczytania i bardziej wyraźny. Widzę, skąd pochodzą, po prostu nie zgadzam się, że dodatkowe rzeczy sprawiają, że jest to łatwiejsze. (Nienawidzę makra, więc jestem stronniczy.) Do ciebie.Nie zgadzam się z twoim argumentem. Jeśli nie otrzymujesz ostrzeżeń dla przydziałów warunkowych, musisz zwiększyć poziomy ostrzeżeń. Proste. (I z miłości do wszystkiego, co dobre, nie zmieniaj ich).
Zauważ, że w C ++ 0x możemy zrobić
if (ptr == nullptr)
, co dla mnie jest przyjemniejsze. (Ponownie, nienawidzę makra. Alenullptr
jest fajne.) Jednak nadal to robięif (ptr)
, tylko dlatego, że jestem do tego przyzwyczajony.źródło
Szczerze mówiąc, nie rozumiem, dlaczego to ma znaczenie. Każdy z nich jest całkiem jasny i każdy średnio doświadczony w C lub C ++ powinien rozumieć oba. Jednak jeden komentarz:
Jeśli planujesz rozpoznać błąd i nie kontynuować wykonywania funkcji (tj. Zamierzasz natychmiast zgłosić wyjątek lub zwrócić kod błędu), powinieneś uczynić z tego klauzulę ochronną:
W ten sposób unikniesz „kodu strzałki”.
źródło
if(!p)
czyli niezdefiniowane zachowanie. To może zadziałać lub nie.if(!p)
to nie jest niezdefiniowane zachowanie, jest to wiersz przed nim. Iif(p==NULL)
miałby dokładnie ten sam problem.Osobiście zawsze używałem,
if (ptr == NULL)
ponieważ jasno określa to mój zamiar, ale w tym momencie to tylko nawyk.Użycie
=
zamiast==
will zostanie przechwycone przez dowolny kompetentny kompilator z poprawnymi ustawieniami ostrzeżeń.Ważne jest, aby wybrać spójny styl dla swojej grupy i trzymać się go. Bez względu na to, którą drogą pójdziesz, w końcu przyzwyczaisz się do tego, a utrata tarcia podczas pracy z kodem innych osób będzie mile widziana.
źródło
Jeszcze jeden punkt na korzyść
foo == NULL
praktyki: jeślifoo
jest, powiedzmy, aint *
lub abool *
, toif (foo)
czek może zostać przypadkowo zinterpretowany przez czytelnika jako testowanie wartości pointee, tjif (*foo)
. Jako .NULL
Porównanie tutaj jest przypomnieniem, że mówimy o wskaźnik.Ale przypuszczam, że dobra konwencja nazewnictwa sprawia, że ten argument jest dyskusyjny.
źródło
Właściwie używam obu wariantów.
Są sytuacje, w których najpierw sprawdzasz poprawność wskaźnika, a jeśli ma on wartość NULL, po prostu wracasz / wychodzisz z funkcji. (Wiem, że może to prowadzić do dyskusji „jeśli funkcja ma tylko jeden punkt wyjścia”)
W większości przypadków sprawdzasz wskaźnik, robisz, co chcesz, a następnie rozwiązujesz przypadek błędu. Rezultatem może być brzydki kod z wcięciem x razy z wieloma ifami.
źródło
goto
może być bardzo przydatne. Również w wielu przypadkach,malloc()
który wymagałby czyszczenia, można zastąpić szybszymalloca()
. Wiem, że nie są zalecane, ale istnieją z jakiegoś powodu (według mnie dobrze nazwana etykietagoto
jest znacznie czystsza niż zaciemnioneif/else
drzewo).alloca
jest niestandardowy i całkowicie niebezpieczny. Jeśli to się nie powiedzie, Twój program po prostu wybuchnie. Nie ma szans na odzyskanie, a ponieważ stos jest stosunkowo mały, prawdopodobne jest niepowodzenie. W przypadku niepowodzenia możliwe jest, że przebijesz stertę i wprowadzisz luki w zabezpieczeniach naruszające uprawnienia. Nigdy nie używajalloca
lub vlas, chyba że masz małe ograniczenie rozmiaru, który zostanie przydzielony (a wtedy równie dobrze możesz po prostu użyć normalnej tablicy).Język programowania C (K&R) wymagałby sprawdzenia null == ptr, aby uniknąć przypadkowego przypisania.
źródło
if (!valid)
powyżejif (valid == 0
).Jeśli styl i format będą częścią twoich recenzji, powinien istnieć uzgodniony przewodnik po stylu, z którym można się zmierzyć. Jeśli istnieje, zrób to, co mówi przewodnik stylu. Jeśli go nie ma, takie szczegóły należy pozostawić tak, jak są zapisane. To strata czasu i energii i odwraca uwagę od tego, co naprawdę powinny być odkrywane recenzje kodu. Poważnie, bez przewodnika po stylu nalegałbym z zasady, aby NIE zmieniać takiego kodu, nawet jeśli nie używa on preferowanej przeze mnie konwencji.
Nie żeby to miało znaczenie, ale moje osobiste preferencje są takie
if (ptr)
. Znaczenie jest dla mnie bardziej oczywiste niż nawetif (ptr == NULL)
.Może próbuje powiedzieć, że lepiej poradzić sobie z warunkami błędu, niż szczęśliwą ścieżką? W takim razie nadal nie zgadzam się z recenzentem. Nie wiem, czy istnieje na to przyjęta konwencja, ale moim zdaniem najbardziej „normalny” stan powinien mieć pierwszeństwo w każdym stwierdzeniu if. W ten sposób mam mniej do zrobienia, aby dowiedzieć się, o co chodzi w tej funkcji i jak działa.
Wyjątkiem jest sytuacja, gdy błąd powoduje wycofanie się z funkcji lub przywrócenie jej przed przejściem dalej. W takich przypadkach najpierw zajmuję się błędem:
Zajmując się z góry nietypowym stanem, mogę się tym zająć, a potem o nim zapomnieć. Ale jeśli nie mogę wrócić na szczęśliwą ścieżkę, zajmując się tym z przodu, należy to załatwić później głównej sprawie, ponieważ czyni to kod bardziej zrozumiałym. W mojej opinii.
Ale jeśli nie jest to przewodnik po stylu, to tylko moja opinia, a Twoja opinia jest równie ważna. Albo standaryzuj, albo nie. Nie pozwól recenzentowi pseudo-standaryzacji tylko dlatego, że ma opinię.
źródło
Jest to jedna z podstaw obu języków, w której wskaźniki oceniają typ i wartość, które mogą być używane jako wyrażenie sterujące,
bool
w C ++ iint
C. Po prostu użyj tego.źródło
if (foo = bar)
przez przypadek.Dlatego wolę
lub
Jednak gdybym pisał zestaw wskazówek dotyczących stylu, nie umieszczałbym w nim takich rzeczy, jak:
źródło
Jestem wielkim fanem tego, że C / C ++ nie sprawdza typy w logicznych warunków
if
,for
orazwhile
sprawozdania. Zawsze używam:nawet na liczbach całkowitych lub innych typach, które konwertują na bool:
Kodowanie w tym stylu jest dla mnie bardziej czytelne i jaśniejsze. Tylko moja osobista opinia.
Ostatnio pracując nad mikrokontrolerem OKI 431 zauważyłem, że:
jest bardziej wydajny niż
ponieważ w późniejszym przypadku kompilator musi porównać wartość chx do 1. Gdzie chx jest po prostu flagą true / false.
źródło
Większość kompilatorów, z których korzystałem, przynajmniej ostrzega przed
if
przypisaniem bez dalszego poprawiania składni, więc nie kupuję tego argumentu. To powiedziawszy, użyłem obu profesjonalnie i nie preferuję żadnego. Jest== NULL
to zdecydowanie jaśniejsze moim zdaniem.źródło