2011-07-21 12 views

Odpowiedz

23

Pierwsza składnia użyć:

if (!someString) 

wykorzystuje rodzaju „dwuznaczność” C wynikającego z faktu, że pierwotny standard C brakowało odpowiedniego typu boolean. Dlatego każda wartość całkowita równa 0 została zinterpretowana jako "fałsz", a każda wartość całkowita różna od "0" została przyjęta jako "prawda". Znaczenie ! jest zatem zdefiniowane w oparciu o tę konwencję, a obecne wersje standardu C zachowały oryginalną definicję kompatybilności.

W Twoim konkretnym przypadku someString jest wskaźnikiem, więc to jest najpierw konwertowane na liczbę całkowitą, a następnie ! someString jest interpretowana jako wartość bool z true gdy someString wskazuje na lokalizację 0x000000, inaczej evals na „true”.

Jest to dobre rozwiązanie w większości przypadków (powiedziałbym zawsze), ale w teorii, NULL/nilcould be different from 0x000000 w niektórych kompilatorów, więc (w samej teorii), że lepiej byłoby użyć drugiego składni, która jest bardziej wyraźne:

if (someString == nil) 

Jest to w każdym razie bardziej czytelne, a ponieważ someString nie jest liczbą całkowitą (raczej wskaźnik), IMO, ogólnie lepszą praktyką.

EDIT: o definicji NULL ...

czy standard C określa NULL się 0 to ciekawy temat dla mnie ...

Według C99 standard, rozdział 7.17, "Wspólne Definicje":

NULL [ce] rozwija się do wskaźnika zerowego stałej realizacji zdefiniowano;

Więc NULL jest zdefiniowana w stddef.h do wdrożenie zdefiniowane zerowy wskaźnik stałej ... tego samego dokumentu na stronie 47 czytamy:

całkowita stałym wyrażeniem o wartości 0, lub takie wyrażenie rzutowane na typ void *, jest nazywane zerowym wskaźnikiem wskaźnika.55) Jeśli stała wskaźnika zerowego jest konwertowana na typ wskaźnika, wynikowy wskaźnik, zwany wskaźnikiem zerowym, gwarantuje porównywanie nierównoległe do wskaźnika do dowolnego obiektu lub funkcji.

więc zerowy wskaźnik stały (który (void*)0) może być przekształconydo wskaźnika zerowego i jest zagwarantowane porównanie różnych od wskaźnika do dowolnego obiektu lub funkcji.

Tak, myślę, że w zasadzie to zależy od tego, czy realizacja zdecyduje, że wynikiem konwersji zerowy wskaźnik stały do zerowego wskaźnika produkuje wskaźnik, który przekształcany z powrotem do liczby całkowitej daje 0. Nie jest jasne że wskaźnik zerowy interpretowany jako liczba całkowita równa 0.

powiedziałbym, że średnia naprawdę spróbować wymusić zerowy wskaźnik ma wartość 0, ale pozostawia otwarte drzwi do systems where the null pointer was not 0.

+2

Dałem +1, ale nie ma dwuznaczności w C na myśl o wartości boolowskiej - po prostu nie istnieje. – Perception

+3

Wartość NULL zdefiniowana jest jako "0" lub "(void *) 0" według standardu C. Nawet jeśli bazowy wzorzec bitowy używany dla wartości wskaźnika pustego jest inny, nie zmienia to faktu, że wskaźnik zerowy stały w C jest reprezentowany jako '0' lub' (void *) 0'. – dreamlax

+0

@Perception: Działa w C99. Sprawdź '_Bool'. – JAB

2

W twoim przypadku oznacza to samo. Każdy wskaźnik, który nie wskazuje na nil, zwróci YES (true).

Zwykle operator wykrzyknika neguje wartość BOOL.

8

Dla większości wskaźników są one równoważne, chociaż większość programistów, których znam, preferuje ten pierwszy, ponieważ jest bardziej zwięzły.

Dla słabo połączonych symboli, pierwszy usuwa symbol (i spowoduje awarię, jeśli go brakuje), podczas gdy wyraźne porównanie z nil lub NULL nie będzie.

0

! to operator negacji. Jeśli obiekt nie zostanie przydzielony, osiągniesz taki sam wynik z tabeli prawdy, jak w przypadku operacji == nil.

Ale! jest zwykle bardziej używany do operacji boolowskich.

if(!isFalse) { 
    //if isFalse == NO, then this operation evaluates to YES (true) 
    [self doStuff]; 
} 

Podczas korzystania ! na obiekcie jak !something po prostu sprawdza, czy wskaźnik wskazuje nil, jeśli nie, to zwraca wartość true, a jeśli pożary oświadczenie.

2

Jeśli chcesz przetestować warunek "foo is nil", powinieneś powiedzieć: foo == nil.

Jeśli chcesz przetestować wartość boolowską dla fałszu, !foo jest w porządku, ale osobiście uważam, że chudy mały wykrzyknik jest łatwy do przeoczenia, więc wolę foo == NO.

Pisanie dobrego kodu polega na wyraźnym przekazaniu intencji nie tylko kompilatorowi, ale także przyszłemu programistce (prawdopodobnie przyszłemu użytkownikowi). W obu przypadkach im bardziej wyraźnie możesz mówić o tym, co próbujesz zrobić, tym lepiej.

Wszystko to na bok, ! i ==nil ma taki sam efekt we wszystkich przypadkach, w których mogę myśleć.

3

Huk, wykrzyknik, ! operator prefiksu w C to logiczny nie. Przynajmniej jego wersja. Jeśli spojrzał na typowym nie jest logiczna tabeli prawdy byłoby zobaczyć coś takiego:

Input  Result 
    1   0 
    0   1 

Jednak w C nie logiczny operator robi coś więcej tak:

Input  Result 
non-zero  0 
    0   1 

Więc jeśli wziąć pod uwagę, że zarówno NULL i zero w Objective-C oceniają na 0, wiesz, że logiczny operator nie zastosowany do nich spowoduje 1.

Teraz należy wziąć pod uwagę operatora równości:==. Porównuje wartość dwóch elementów i zwraca 1, jeśli są równe, 0, jeśli nie są równe. Jeśli zmapowałeś jej wyniki na tabelę prawdy, to wyglądałoby dokładnie tak, jak w przypadku wyników logicznych.

W programach C i Objective-C warunkowość jest faktycznie określana przez int, w przeciwieństwie do prawdziwych booleans. To dlatego, że nie ma czegoś takiego jak typu boolean danych w C. Więc pisząc coś takiego działa perfekcyjnie w C:

if(5) printf("hello\n"); // prints hello 

a ponadto

if(2029) printf("hello\n"); // also prints hello 

Zasadniczo, każdy nie- zerowy int oceni jako „prawdziwy” w C można połączyć to z tabel prawdy dla logicznej negacji i równości, i szybko sobie sprawę, że:

(! someString) and (someString == nil) 

są dla wszystkich zamiarów id fascynujący!

Następne logiczne pytanie brzmi: dlaczego preferować jedną formę nad inną? Z czystym C widzenia punktu byłoby głównie punktem stylu, ale większość (dobre) programistów wybrałby test równości z kilku powodów:

  1. jest bliżej do tego, co starają się wyrazić w kodzie . Użytkownik: jest próbuje sprawdzić, czy zmienna someString jest zerowa.
  2. Jest bardziej przenośny. Języki takie jak Java mają prawdziwy typ boolowski. Nie można używać notacji typu bang w swoich zmiennych ani definicji NULL . Korzystanie z równości tam, gdzie jest to potrzebne, ułatwia później przeniesienie do takich języków C.
  3. Apple może zmienić definicję zero. Ok, nie, nie będą! Ale to nigdy nie boli, aby być bezpiecznym!
+0

"dowolna niezerowa wartość int zostanie określona jako" prawdziwa "w C" Czy mógłbyś/powinnaś bardziej szczegółowo wyjaśnić, w jaki sposób wyrażenia logiczne są oceniane na (int) 0 lub (int) 1? Powiedz, [if (wskaźnik) ...], wskaźnik jest najpierw konwertowany na wskaźnik int [(int)], a następnie [if ((int) point! = 0)] ocenia na (int) 1. Możliwe, że wskaźnik jest 64-bitowy, a int - 32-bitowy, a gdy jest rzutowany na int, wyższe bajty są obcięte (jeśli (0xffffffff00000000) => if ((int) 0x00000000))? Cieszę się, że mogę się mylić. –

Powiązane problemy