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ó.