Czy większość programistów aplikacji używa podpisanych liczb całkowitych w miejscach, w których naprawdę chcą używać liczb całkowitych bez znaku? Robię to cały czas, podobnie jak moi współpracownicy. Nie widziałem wielu innych obszernych baz kodu (innych niż Delphi VCL), a przykłady w Internecie zwykle używają liczb całkowitych. Podczas gdy programiści VCL używają własnych typów danych (co byłoby najbardziej leniwym sposobem na zadeklarowanie zmiennych).
Coś takiego wydaje się trochę przerażające w takim kodzie
TStuffRec = record
recordID : Integer;
thingID : Integer;
otherThingID : Integer;
end;
kiedy można to zapisać jako
TStuffRec = record
recordID : Cardinal;
thingID : Cardinal;
otherThingID : Cardinal;
end;
Funkcjonalnie te rekordy prawie zawsze działają tak samo (i mam nadzieję, że będą nadal działać tak samo, nawet w 64-bitowym Delphi). Ale bardzo duże liczby będą miały problemy z konwersją.
Ale są też wady używania niepodpisanych int. Wynika to głównie z tego, jak denerwujące jest mieszanie tych dwóch.
Prawdziwe pytanie brzmi: czy jest to rzecz, o której naprawdę się myśli lub która jest uwzględniana w najlepszych praktykach? Czy zwykle zależy to od programisty?
źródło
Odpowiedzi:
Jednym z powodów, dla których nie używam tak często liczb całkowitych bez znaku w Delphi, jest to, że mogą powodować problemy po zmieszaniu z podpisanymi liczbami całkowitymi. Oto jeden, który mnie raz ugryzł:
Miałem
i
zadeklarowane jako liczba całkowita bez znaku, (mimo wszystko, jest to wskaźnik do listy, która rozpoczyna się od 0, to nigdy nie musi być ujemna, prawda?), Ale kiedyList.Count
było 0, to nie zwarcie pętli zgodnie z oczekiwaniami, ponieważ0 - 1
ocenia na naprawdę wysoką liczbę dodatnią. Ups!Pomiędzy potencjalnymi problemami związanymi z bezpieczeństwem związanymi z mieszaniem liczb całkowitych ze znakiem i bez znaku oraz problemami z zasięgiem (jeśli będziesz potrzebować liczb dodatnich większych niż
high(signed whatever)
, jest całkiem prawdopodobne, że również będziesz potrzebować liczb dodatnich większychhigh(unsigned whatever)
, więc poruszasz się do następnego większego rozmiaru zamiast przełączania z podpisanego na niepodpisany o tym samym rozmiarze jest zwykle poprawną czynnością). Naprawdę nie znalazłem zbyt wielu zastosowań dla liczb całkowitych bez znaku, gdy reprezentuję większość danych.źródło
Szczerze mówiąc, zwykle używam liczb całkowitych z przyzwyczajenia. Przyzwyczaiłem się, że oferują zakresy wystarczająco duże dla większości sytuacji i pozwalają na wartości ujemne (takie jak -1). Rzeczywiście, wiele razy użycie bajtów / słów / skrótów byłoby bardziej odpowiednie. Teraz myśląc o tym, mogę skupić się na tych miejscach:
Perspektywiczny. Rozmiar Tilemap jest ograniczony do 192x192 kafelków, więc mógłbym użyć bajtu do adresowania kafelków i pętli. Ale jeśli rozmiar mapy zostanie zwiększony, będę musiał przejść przez każde użycie i zastąpić go np. Słowem. Kiedy muszę zezwolić na obiekty poza mapą, musiałbym wrócić jeszcze raz, aby przejść na smallint.
Pętle Często piszę pętlę „od i: = 0 do Count-1”, co dzieje się, gdy „i” jest bajtem, a Count = 0 oznacza, że pętla działa od 0 do 255. Nie, żebym tego chciał.
Uniforming. Łatwiej jest zapamiętać i zastosować „var i: integer;” niż zatrzymać się w każdym przypadku i pomyśleć „Hm .. tutaj mamy do czynienia z zakresem 0..120 .. bajt .. nie, czekaj, możemy potrzebować -1 dla niezainicjowanego .. skrótu .. czekaj .. co jeśli 128 to za mało .. Arrgh! " lub „Dlaczego jest to małe miejsce w tym miejscu, a nie skrót?”
Łączenie Kiedy muszę połączyć dwie lub więcej klas razem, mogą one używać różnych typów danych do swoich celów, użycie szerszych typów pozwala pominąć niepotrzebne konwersje.
-1. Nawet gdy wartości mieszczą się w zakresie 0..n-1, często muszę ustawić wartość „brak wartości / nieznana / niezainicjowana / pusta”, co jest powszechną praktyką -1.
Korzystanie z liczb całkowitych pozwala pominąć wszystkie te problemy, zapomnieć o optymalizacji niskiego poziomu tam, gdzie nie jest to potrzebne, przejść na wyższy poziom i skupić się na bardziej realnych problemach.
PS Kiedy używam innych typów?
źródło
Najlepszą praktyką jest użycie typu danych, który odpowiada potrzebom wykorzystywanych danych (dane oczekiwane).
Przykłady C #: Gdybym tylko musiał obsługiwać od 0 do 255, użyłbym bajtu.
Gdybym musiał wesprzeć 1 000 000 negatywnych i pozytywnych, to int.
Większy niż 4,2 miliarda, a następnie użyj długiego.
Wybierając odpowiedni typ, program będzie korzystał z optymalnej ilości pamięci, a różne typy używają różnych ilości pamięci.
Oto odwołanie do C # int z MSDN.
źródło
Integer
typ danych to 32 bity na maszynie 32-bitowej i najwyraźniej będą to 64 bity na maszynie 64-bitowej.int
to tylko skrótSystem.Int32
, bez względu na to, na jakiej maszynie działa kod.type int System.Int32
coś takiego? Czy można to łatwo zmienić w przyszłej wersji frameworka?uint
jest jednym z takich niezgodnych typów, co oznacza, że nie należy go używać w publicznie dostępnym interfejsie API, aby uniknąć zerwania możliwości korzystania z tego interfejsu API w językach .NET innych niż język, w którym biblioteka jest napisana. Z tego też powodu platforma .NET Sam API używaint
gdzieuint
by to zrobił.Niepodpisane typy liczb całkowitych powinny być używane tylko do reprezentowania liczb kardynalnych w językach, w których reprezentują liczby kardynalne. Ze względu na sposób, w jaki działały komputery z systemem C, niepodpisane typy liczb całkowitych zachowywały się jako elementy pierścieni algebraicznych mod-2 ^ n (co oznacza, że przepełnione obliczenia „zawiną się” przewidywalnie), a język określa, że w wielu przypadkach takie typy są wymagane, by zachowywały się jak abstrakcyjne pierścienie algebraiczne, nawet jeśli takie zachowanie byłoby niezgodne z zachowaniem liczb głównych lub liczb matematycznych.
Jeśli platforma w pełni wspierała osobne typy dla liczb głównych i pierścieni algebraicznych, sugerowałbym, że liczby główne powinny być przetwarzane przy użyciu typów liczb głównych (i rzeczy, które muszą się zawijać przy użyciu typów pierścieni). Takie typy mogą nie tylko przechowywać liczby dwa razy większe niż typy podpisane, ale metoda otrzymująca parametr takiego typu nie musi sprawdzać, czy jest ujemna.
Biorąc jednak pod uwagę względny brak typów liczb kardynalnych, zazwyczaj najlepiej jest po prostu używać liczb całkowitych do reprezentowania zarówno liczb matematycznych, jak i liczb głównych.
źródło