Dlaczego krótkie, int i długie zostały wynalezione w C?

16

Mam problemy ze zrozumieniem, jakie były dokładne cele tworzenia short, inti longtypy danych w C?

Powód, o który pytam, nie wygląda na to, że ich rozmiary są ograniczone - mogą mieć dowolny rozmiar, o ile na przykład shortjest mniejszy niż jeden int.

W jakich sytuacjach powinieneś użyć unsigned intlub unsigned long, na przykład, zamiast a size_t, gdy nie daje to żadnej nadziei na zgodność binarną?

(Jeśli nie znasz rozmiaru, to skąd wiesz, kiedy wybrać, który?)

użytkownik541686
źródło
2
Sprawdź<stdint.h>
BlackJack,
1
@BlackJack: Haha tak, tak naprawdę - ale myślę, że moje pytanie brzmi: dlaczego nie wszystkie typy są zdefiniowane natywnie? Czy jest to problem „z perspektywy czasu 20/20”, czy może był jakiś konkretny powód?
user541686,
2
C miał być zarówno przenośny, jak i leżący w pobliżu podstawowego sprzętu. Były platformy, na których bajt nie był 8-bitowy - ale nadal można było użyć C. Żaden stały zestaw typów danych nigdy nie byłby wystarczający, żadna liczba całkowita o stałym rozmiarze nigdy nie byłaby przenośna.
SK-logic
@ SK-logic: Nawet jeśli powiedzieli sizeof(short) == 2 * sizeof(char)lub podobni?
user541686,
1
Istnieją platformy, na których sizeof(char) == sizeof(short)ma to sens. Niestety nie ma sposobu na określenie liczb całkowitych w taki sposób, aby pasowały one do wszystkich możliwych i istniejących platform.
SK-logic

Odpowiedzi:

12

Będzie to określone przez architekturę, której używasz. Na układzie Zilog z80 (wspólny układ osadzony) byłyby jednego rozmiaru, podczas gdy na chipsecie x86 mogłyby mieć zupełnie inny rozmiar. Jednak same rozmiary są względem siebie ustalonymi proporcjami. Zasadniczo krótkie i długie nie są typami, ale kwalifikują się do typu int. Krótkie ints będą o jeden rząd wielkości mniejsze niż (zwykłe) int, a long ints będą o rząd wielkości wyższe. Powiedzmy, że twoja Int jest ograniczona do 4 bajtów, krótki kwalifikator ogranicza ją do 4 bajtów, chociaż 2 bajty są również bardzo częste, a długi kwalifikator zwiększa ją potencjalnie do 8 bajtów, chociaż może być mniejszy do 4 bajtów. Należy pamiętać, że zależy to również od długości słowa, więc w systemie 32-bitowym i tak możesz uzyskać maksymalnie 4 bajty na int, co daje tyle samo co zwykłe int. Zatem Short ≤ Int ≤ Long.

Jeśli jednak wydłużysz go ponownie, możesz wcisnąć int do następnej komórki, co daje 8 całych bajtów pamięci. Jest to rozmiar słowa dla maszyn 64-bitowych, więc nie muszą się one martwić o takie rzeczy i po prostu używają jednej komórki dla długich liczb całkowitych, co pozwala im być kolejną kolejnością powyżej standardowych liczb wewnętrznych, podczas gdy długie długie cyfry stają się naprawdę bitowe.

Jeśli chodzi o wybór, sprowadza się do czegoś, na co programiści Java nie muszą się martwić. „Jaka jest twoja architektura?” Ponieważ wszystko zależy od wielkości słowa pamięci danego urządzenia, musisz zrozumieć to z góry, zanim zdecydujesz, którego użyć. Następnie wybierasz najmniejszy rozsądny rozmiar, aby zaoszczędzić jak najwięcej pamięci, ponieważ pamięć ta zostanie przydzielona niezależnie od tego, czy użyjesz wszystkich bitów, czy nie. Więc oszczędzasz, gdzie możesz i wybierasz szorty, kiedy możesz, i ints, kiedy nie możesz i jeśli potrzebujesz czegoś większego niż to, co dajesz zwykłym intymnym; wydłużysz w razie potrzeby, dopóki nie uderzysz w słowo sufit. Następnie musisz podać procedury dużej liczby lub pobrać je z biblioteki.

C może być „przenośnym zestawem”, ale nadal musisz znać swój sprzęt.

Inżynier świata
źródło
11
to nie do końca dobrze, szorty nie muszą być mniejsze niż ints, nie mogą być większe niż ints
jk.
Naprawię to.
Inżynier świata
2
Podobnie, długie nie mogą być mniejsze niż ints.
Donal Fellows,
1
w rzeczy samej uważam, że były maszyny, w których krótkie, wewnętrzne i długie były dokładnie takie same.
jk.
6

Chociaż dzisiaj „bajt” oznacza „8 bitów”, nie zawsze tak było. Maszyny wykorzystały adresowalne fragmenty 4 bitów, 8 bitów, 12 bitów, 16 bitów, 32 bitów i 36 bitów (i prawdopodobnie także inne rozmiary). Jednym z założeń projektowych C było zastosowanie na maszynach o różnych rozmiarach i konfiguracjach pamięci.

Myślę, że pierwotnie zamierzeniem projektu było, aby każdy typ intbył najmniejszą rzeczą, która mogła poradzić sobie z liczbami o różnych rozmiarach, i że intbyłby to najbardziej praktyczny rozmiar „ogólnego zastosowania”, który mógłby obsłużyć +/- 32767. Nie wydaje mi się, aby istniała chęć lub zamiar stworzenia języka, który byłby nadal używany, gdy komputery stały się tak potężne, że operacje na liczbach 64-bitowych kosztują tyle samo, co operacje na mniejszych.

Największy problem z semantyką typu całkowitoliczbowego C polega na tym, że w niektórych kontekstach reprezentują one liczby kardynalne lub liczby całkowite matematyczne, podczas gdy w innych kontekstach są używane do reprezentowania członków otulającego abstrakcyjnego algebraicznego pierścienia liczb całkowitych przystających mod 2 ^ n [np. Odejmowanie maksymalna reprezentowalna wartość od 0 jest określona, ​​aby dać 1], ale zachowania są określone bardziej na podstawie tego, co wydawały się robić kompilatory w czasach, gdy rozmiary słów komputerowych wynosiły około 16 bitów (a rozmiar słów 36-bitowych byłby ogromny ), a nie na podstawie tego, co ma sens na komputerze 64-bitowym. W konsekwencji wynik odejmowania 32-bitowej wartości bez znaku od mniejszej 32-bitowej wartości bez znaku może być dużą 32-bitową wartością bez znaku lub ujemną liczbą 64-bitową.

supercat
źródło
4

/programming/589575/size-of-int-long-etc

Tak więc w najczęściej używanych architekturach char to 1 bajt, short i int to co najmniej 2 bajty, a long to co najmniej 4 bajty.

I intencją jest, aby „int” był najbardziej naturalną / normalną / wydajną reprezentacją dla bieżącego procesora.

Zatem ogólną zasadą jest używanie „int”, chyba że twoje wartości przekraczają +/- 32K, co powoduje, że (na starszych procesorach) używasz „długiego”. ... lub chyba, że ​​tworzysz duże tablice małych (<32 KB) wartości, a pamięć stanowi problem - więc użyjesz „krótkiego”, aby zaoszczędzić pamięć (a może „char” lub „byte”).

Jeff Grigg
źródło
2
Ale w wersji 64-bitowej intrzadko jest dobrym wyborem, prawda? I tak prawie zawsze używam size_t(a nawet ptrdiff_t!), Aby uniknąć problemów z kodowaniem.
user541686,
@Merhdad - przyzwyczajeni do najlepszego wyboru zdefiniowano go jako „standardową jednostkę” sprzętu i zazwyczaj ma on rozmiar wskaźnika. W dzisiejszych czasach używaj size_t dla bezpieczeństwa.
Martin Beckett,
1

C został zaprojektowany, aby aktywnie radzić sobie z pamięcią na różnych poziomach. Są przypadki, w których różnica między skrótem, intem i długością oraz pomiędzy zmiennoprzecinkowym i podwójnym ma znaczenie ze względu na ograniczenia pamięci, architekturę itp. Mimo że teraz nie ma to większego znaczenia, nadal istnieją środowiska, w których to robi (np. Osadzone i w przypadki, w których dane są ogromne), a przejście z głównie architektur 32-bitowych na 64-bitowe sprawia, że ​​znów stanowi to problem. (Za dziesięć lub dwadzieścia lat, kiedy przejdziemy do architektur 128-bitowych, a C / C ++ jest nadal popularny, znowu będzie to problemem). Masz jednak rację, że binarna kompatybilność cierpi, dlatego nie chcesz używać tych rozmiarów zmiennych, jeśli to ma znaczenie.

Zapytałeś, skąd wiesz, którego użyć, jeśli nie znasz rozmiaru, ale znasz rozmiar danej kombinacji architektury / kompilatora, a jeśli chcesz zoptymalizować pamięć na tym poziomie, lepiej go poznaj. Nie możesz zoptymalizować tego po prostu na różnych platformach, ponieważ nie znasz ich rozmiarów, więc nie chcesz używać tych funkcji do tego celu. Ale wiele rzeczy napisanych w C jest specyficznych dla platformy, co pomimo mody na „cross platform”, pozwala na pewne korzystne optymalizacje.

Kylben
źródło