Bardzo dobre pytanie :)
lukasz1235 napisał:
signed char przechowuje liczby ze znakiem
unsigned char przechowuje liczby bez znaku
char to signed char lub unsigned char (w zależności od implementacji)
W zasadzie jest to poprawnie, natomiast warto doprecyzować, że wg standardu (sprawdzałem w draftach od C1X, C++0x oraz w finalnej wersji C89) typ "char" pozwala przechować jeden dowolny znak z podstawowego zestawu znaków, do tego gwarantując, że wartość (kod) tego znaku będzie nieujemna (w C89 było użyte słowo "dodatnia"; w C++0x takowego zapewnienia nie widzę).
Czyli "char" jako tako nie jest przez standard definiowane jako typ liczbowy, natomiast "signed char" oraz "unsigned char" już tak (za draftem C++0x: [...] char, signed char, and unsigned char are three distinct types).
Jak zauważył lukasz1235, typ char zazwyczaj jest implementowany po prostu jako albo "signed char" albo "unsigned char" (kwestia na jaki kompilator / architekturę się trafi).
Również (ku mojemu zaskoczeniu) jest w standardach jasno powiedziane, że sizeof(char), sizeof(signed char) oraz sizeof(unsigned char) ma zwracać 1 bajt.
Jeśli chodzi o typy: short, short int, signed short, signed short int, int, long int, etc, to kolejno:
Pełną nazwą typu jest "signed char" i nie ma innych nazw.
Pełną nazwą typu jest "short int", ale można też stosować: "short", "signed short", "signed short int".
Pełną nazwą typu jest "int", ale można też stosować: "signed int" lub "signed"
Pełną nazwą typu jest "long int", ale można też stosować: "long", "signed long", "signed long int".
Pełną nazwą typu jest "long long int", ale można też stosować: "long long", "signed long long", "signed long long int"
Jeśli chodzi o typy unsigned, to jest trochę mniej wyboru:
Pełną nazwą typu jest "unsigned char" i nie ma innych nazw.
Pełną nazwą typu jest "unsigned short int", ale można też pisać: "unsigned short"
Pełną nazwą typu jest "unsigned int", ale można też pisać: "unsigned"
Pełną nazwą typu jest "unsigned long int", ale można też pisać: "unsigned long"
Pełną nazwą typu jest "unsigned long long int", ale można też pisać: "unsigned long long"
Dodam jeszcze, że typ [unsigned] long long int został dodany dopiero w nowych standardach (wcześniej go nie było).
Jeśli chodzi o wielkości, to sprawa się trochę komplikuje między C a C++. Zacznijmy od C++.
W C++ jedyne co standard mówi, to tyle, że:
- int ma mieć wielkość natywną dla danej architektury
- ma być spełniona następująca zależność:
sizeof(signed char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)
- nie ma podanych konkretnych wielkości dla konkretnych typów.
(z tego co mi się obiło o uszy to na którejś wersji Craya było 1 <= 1 <= 1 <= 1, natomiast znalazłem jedynie info o 1 <= 8 <= 8 <= 8).
W C natomiast standard podaje dodatkowo "minimalne" zakresy dla powyższych zmiennych (przez minimalne rozumiem że zmienna może mieć większy zakres, ale musi mieć przynajmniej taki jak podano):
Kolejno:
signed char: -127 (sic) do 127
short int: -32767 (sic) do 32767
int: -32767 (sic) do 32767 (sic; przypominam, że to draft c1x ;>)
long int: -2147483647 (sic) do 2147483647
long long int: -9223372036854775807 (sic) do 9223372036854775807
A jeśli chodzi o unsigned (od 0 do ...):
unsigned char: 255 (czyli 2^8 - 1)
unsigned short int: 65535 (czyli 2^16 - 1)
unsigned int: 65535 (sic) (czyli 2^16 - 1)
unsigned long int: 4294967295 (czyli 2^32 - 1)
unsigned long long int: 18446744073709551615 (czyli 2^64 - 1)
Natomiast, jeśli chodzi o konkretne zakresy, to sugeruje dla pewności sprawdzić jak bierzesz do ręki nowy kompilator/architekturę/system - czasem można się przejechać ;> (np. 64-bitowym x86 na Windowsowych kompilatorach sizeof(long) zwraca 4, a na GNU/Linux zwraca 8).
Dodam, że jeśli Ci zależy na konkretnych długościach zmiennych i chcesz być przenośny między architekturami, to warto rzucić okiem na nagłówek stdint.h w C oraz cstdint w C++ - są tam podeklarowane typy względem wielkości (chociaż bodajże różni się to między C a C++ oraz między kompilatorami / zestawami nagłówków).