A C nyelv tÃpusrendszere egész számok tekintetében a processzor bitjeihez és az operációs rendszerhez kötött. 32 és 64 bites rendszerek esetén az int 32 bites, de szabvány szerint legalább egy 16 bitesnek kell lennie. A C alapvetÅ‘en nem támogat sok primitÃv tÃpust. int, char, float és double tÃpusai vannak. A float és a double a IEEE 754 szabvány szerinti 32 bites és 64 bites lebegÅ‘pontos számokat jelölik.
A char egy darab ASCII kódolású karaktert reprezentál. Unicode karakter leÃrására a wchar_t tÃpus alkalmazható, ami implementációtól függÅ‘en 16 vagy 32 bites unicode kódolású karaktert is jelenthet.
Az alábbi táblázat az alap tÃpusok tipikus méreteit tartalmazza x86 és x64 Windows rendszerek esetén bitekben:
| TÃpus | Bitek száma |
|---|---|
int |
32 |
float |
32 |
double |
64 |
char |
8 |
wchar_t |
16 |
Az egész tÃpus esetén a short "felezi" az int tÃpus bitjeinek számát, mÃg a long "duplázza". ElÅ‘jelet megfosztani azunsigned módosÃtóval tudunk, aminek a párja a signed, ha explicit jelezni szeretnénk, hogy elÅ‘jeles tÃpusról beszélünk.
Az elÅ‘zÅ‘ bekezdésben a felezi és a duplázza szó nem véletlenül került idézÅ‘jelbe, mivel nagymértékben egyszerűsÃti a magyarázatot. Sajna a valóság kicsivel komplikáltabb, mivel ezek jelentése fordÃtó és operációs rendszer függÅ‘ is. Olyan rendszerek esetén, ahol eleve 16 bites az int tÃpus (Pl. 8 bites MikrovezérlÅ‘k), ott a short nem fog 8 bites egészt jelenteni, ugyanúgy egy 16 bites egészt jelent. A long működése még komplikáltabb, mivel 32 bites Windows és gcc esetén a long ugyanúgy 32 bit, mint az int. Azonban Linux és gcc esetén a long 32 bites rendszeren is 64 bitet jelent.
A short és a long önmagukban is elfogadott tÃpusok, nem kell mögéjük Ãrni az int tÃpust. Ugyanez igaz a signed és unsigned esetén is: ezek is állhatnak önmagukban. Ebben az esetben a fordÃtó az int tÃpusjelzÅ‘t feltételezi.
A módosÃtók és az int gép és fordÃtó függÅ‘sége miatt született egy szabványosÃtott egész tÃpus rendszer, amit az stdint.h header használatával tudunk igénybevenni. Egész számok esetén ezeket érdemes alkalmazni tÃpus jelölésre, mert Ãgy garantáltan hordozható lesz a kódunk, illetve a tÃpus nevébÅ‘l egyértelműen kiderül annak a mérete. Az stdint.h int_méret_t formában definiál egész tÃpusokat, ahol a méret lehet 8, 16, 32 vagy 64.
| TÃpus | Bitek száma | Minimum | Maximum |
|---|---|---|---|
int8_t |
8 | INT8_MIN |
INT8_MAX |
int16_t |
16 | INT16_MIN |
INT16_MAX |
int32_t |
32 | INT32_MIN |
INT32_MAX |
int64_t |
64 | INT64_MIN |
INT64_MAX |
uint8_t |
8 | 0 |
UINT8_MAX |
uint16_t |
16 | 0 |
UINT16_MAX |
uint32_t |
32 | 0 |
UINT32_MAX |
uint64_t |
64 | 0 |
UINT64_MAX |
A C történelmébÅ‘l adódóan biztos, hogy találkozni fogunk legacy, bÅ‘ven az univerzális tÃpus méretek bevezetése elÅ‘tt Ãródott kóddal, amiben a módosÃtók széles palettájával alkotott tÃpusokkal kell majd dolgoznunk. Az alábbiakban az összes elfogadott módosÃtó és tÃpus kombinációt olvashatjuk:
-
char(8 bit minimum)A char a gép által megcÃmezhetÅ‘ legkisebb egység, ami egy karaktert reprezentál. Egész számként tárolódik, ami lehet elÅ‘jeles vagy elÅ‘jel nélküli platform és fordÃtó függÅ‘en.
-
signed char(8 bit minimum)A
chartÃpus garantáltan elÅ‘jeles változata. -
unsigned char(8 bit minimum)A
chartÃpus garantáltan elÅ‘jel nélküli változata. -
short,short int,signed short,signed short int(16 bit minimum)Előjeles egész szám, amely legalább 16 biten tárolódik.
-
unsigned short,unsigned short int(16 bit minimum)Előjel nélküli egész szám, amely legalább 16 biten tárolódik.
-
int,signed,signed int(16 bit minimum)Előjeles egész szám, amely legalább 16 biten tárolódik.
-
unsigned,unsigned int(16 bit minimum)Előjel nélküli egész szám, amely legalább 16 biten tárolódik.
-
long,long int,signed long,signed long int(32 bit minimum)Előjeles egész szám, amely legalább 32 biten tárolódik.
-
unsigned long,unsigned long int(32 bit minimum)Előjel nélküli egész szám, amely legalább 32 biten tárolódik.
-
long long,long long int,signed long long,signed long long int(64 bit minimum)Előjeles egész szám, amely legalább 64 biten tárolódik.
-
unsigned long long,unsigned long long int(64 bit minimum)Előjel nélküli egész szám, amely legalább 64 biten tárolódik.
-
long doubleLebegÅ‘pontos tÃpus, aminek a tényleges tulajdonságai nem definiáltak a szabvány által. Reprezentálhat x86 extended precisiont 80 vagy 96 biten, vagy IEEE 754 szerinti 128 bites lebegÅ‘pontos formátumot, de az is megengedett, hogy ekvivalens legyen a double-el.
TÃpus méretek ellenÅ‘rzése
Az alábbi példaprogram a tÃpus méretek ellenÅ‘rzésére szolgál:
#include <stdio.h>
/*A tÃpusok minimum és maximum konstansait tartalmazza*/
#include <limits.h>
/*float és double tÃpusokhoz tartozó minimum és maximum konstansok*/
#include <float.h>
int main()
{
printf("char: %lld, min: %c max: %c\r\n",
sizeof(char) * 8, CHAR_MIN, CHAR_MAX);
printf("signed char: %lld, min: %hhi max: %hhi\r\n",
sizeof(signed char) * 8, SCHAR_MIN, SCHAR_MAX);
printf("unsigned char: %lld, min: %hhu max: %hhu\r\n",
sizeof(unsigned char) * 8, 0, UCHAR_MAX);
printf("short: %lld, min: %hd max: %hd\r\n",
sizeof(short) * 8, SHRT_MIN, SHRT_MAX);
printf("unsigned short: %lld, min: %hu max: %hu\r\n",
sizeof(short) * 8, 0, USHRT_MAX);
printf("int: %lld, min: %d max: %d\r\n",
sizeof(int) * 8, INT_MIN, INT_MAX);
printf("unsigned: %lld, min: %u max: %u\r\n",
sizeof(unsigned int) * 8, 0, UINT_MAX);
printf("long: %lld, min: %ld max: %ld\r\n",
sizeof(long) * 8, LONG_MIN, LONG_MAX);
printf("unsigned long: %lld, min: %lu max: %lu\r\n",
sizeof(unsigned long) * 8, 0, ULONG_MAX);
printf("long long: %lld, min: %lld max: %lld\r\n",
sizeof(long long) * 8, LLONG_MIN, LLONG_MAX);
printf("unsigned long long: %lld, min: %llu max: %llu\r\n",
sizeof(unsigned long long) * 8, 0, ULLONG_MAX);
printf("float: %lld, min: %E max: %e\r\n",
sizeof(float) * 8, FLT_MIN, FLT_MAX);
printf("double: %lld, min: %lE max: %lE\r\n",
sizeof(double) * 8, DBL_MIN, DBL_MAX);
printf("long double: %lld, min: %lE max: %lE\r\n",
sizeof(long double) * 8, LDBL_MIN, LDBL_MAX);
return 0;
}
A program kimenete 32 bites x86 fordÃtó esetén:
char: 8 bits, min: Ç max: ⌂
signed char: 8 bits, min: -128 max: 127
unsigned char: 8 bits, min: 0 max: 255
short: 16 bits, min: -32768 max: 32767
unsigned short: 16 bits, min: 0 max: 65535
int: 32 bits, min: -2147483648 max: 2147483647
unsigned: 32 bits, min: 0 max: 4294967295
long: 32 bits, min: -2147483648 max: 2147483647
unsigned long: 32 bits, min: 0 max: 4294967295
long long: 64 bits, min: -9223372036854775808 max: 9223372036854775807
unsigned long long: 64 bits, min: 18446744069414584320 max: 9223372036854775807
float: 32 bits, min: 1.175494E-38 max: 3.402823e+38
double: 64 bits, min: 2.225074E-308 max: 1.797693E+308
long double: 96 bits, min: -0.000000E+00 max: NAN
A program kimenete 64 bites x86 fordÃtó esetén:
char: 8 bits, min: Ç max: ⌂
signed char: 8 bits, min: -128 max: 127
unsigned char: 8 bits, min: 0 max: 255
short: 16 bits, min: -32768 max: 32767
unsigned short: 16 bits, min: 0 max: 65535
int: 32 bits, min: -2147483648 max: 2147483647
unsigned: 32 bits, min: 0 max: 4294967295
long: 32 bits, min: -2147483648 max: 2147483647
unsigned long: 32 bits, min: 0 max: 4294967295
long long: 64 bits, min: -9223372036854775808 max: 9223372036854775807
unsigned long long: 64 bits, min: 0 max: 18446744073709551615
float: 32 bits, min: 1.175494E-38 max: 3.402823e+38
double: 64 bits, min: 2.225074E-308 max: 1.797693E+308
long double: 128 bits, min: 5.214287E-312 max: 5.214287E-312
TÃpusmódosÃtók
-
auto
A változót csak abban a blokkban teszi láthatóvá, ahol a változó definiálva van. Alapértelmezetten nincs értéke, definiáláskor meg kell adni egy kezdőértéket. Nem kötelezÅ‘ a használata, hiszen az összes változó e módon jön létre. A C23 szabvány óta a tÃpus automatikus kikövetkeztetésére is használható, hasonlóan ahhoz, mint amit a C++ már a C++11 szabvány óta tud.
-
const
Hatására a változó értéke konstanssá válik, egyszer lehet neki értéket adni a változó definiálásakor, később nem.
-
extern
Azt jelzi a fordÃtó számára, hogy az extern módosÃtóval megjelölt változó egy másik forrásfájlban van definiálva. Ezzel a módszerrel egy másik forráskód fájljában definiált változó értékéhez hozzáférhetünk. Továbbá az extern kulcsszó használható függvények elÅ‘tt is.
-
register
Hatására a változó egy CPU regiszterben tárolódik a memória helyett. Ez nem biztosÃtható minden esetben, úgyhogy a fordÃtó csak egy ajánlásnak veszi fordÃtás közben, ha nincs akadálya a register tárolási módnak, akkor használni fogja.
-
static
Hatására a változó statikus lesz. Amennyiben egy változó statikusnak van jelölve egy függvényben, akkor értékét megÅ‘rzi a funkcióhÃvások közben is.
-
volatile
Azt jelzi a fordÃtónak, hogy a változó által használt memóriaterületet a futó programon kÃvül más is módosÃthatja. Az ilyen módon megjelölt változók esetén a fordÃtó nem optimalizál látszólag felesleges dolgokat. Például:
x = 0; x = 1;kódban ha x nemvolatile, akkor azx = 0értékadást kioptimalizálja a fordÃtó.