Tipuri de date C - C data types

În limbajul de programare C , tipurile de date constituie semantica și caracteristicile stocării elementelor de date. Acestea sunt exprimate în sintaxa limbii sub formă de declarații pentru locațiile de memorie sau variabile . Tipurile de date determină, de asemenea, tipurile de operații sau metodele de prelucrare a elementelor de date.

Limbajul C oferă tipuri de bază aritmetice, cum ar fi tipuri de numere întregi și numere reale , și sintaxă pentru a construi tipuri de matrice și compuse. Anteturile pentru biblioteca standard C , care urmează să fie utilizate prin intermediul directivelor , conțin definiții ale tipurilor de suport, care au proprietăți suplimentare, cum ar fi furnizarea de stocare cu o dimensiune exactă, independent de implementarea limbajului pe platforme hardware specifice.

Tipuri de bază

Principalele tipuri

Limbajul C oferă cele patru specificații de bază aritmetice de tip char , int , float și double , iar modificatorii semnați , nesemnați , scurți și lungi . Următorul tabel listează combinațiile permise în specificarea unui set mare de declarații specifice dimensiunii stocării.

Tip Explicaţie Dimensiune minimă (biți) Specificator de format
char Cea mai mică unitate adresabilă a mașinii care poate conține un set de caractere de bază. Este un tip întreg . Tipul real poate fi semnat sau nesemnat. Conține biți CHAR_BIT. 8 %c
signed char De aceeași dimensiune ca și char , dar garantat că va fi semnat. Capabil să conțină cel puțin intervalul [-127, +127]. 8 %c (sau %hhipentru ieșire numerică)
unsigned char De aceeași dimensiune ca și char , dar garantat că este nesemnat. Conține cel puțin intervalul [0, 255]. 8 %c (sau %hhupentru ieșire numerică)
short
short int
signed short
signed short int
Tip întreg semnat scurt . Capabil să conțină cel puțin intervalul [-32.767, +32.767]. 16 %hi sau %hd
unsigned short
unsigned short int
Tip întreg nesemnat scurt . Conține cel puțin intervalul [0, 65.535]. 16 %hu
int
signed
signed int
Tip întreg de bază semnat. Capabil să conțină cel puțin intervalul [-32.767, +32.767]. 16 %i sau %d
unsigned
unsigned int
Tipul de bază întreg nesemnat. Conține cel puțin intervalul [0, 65.535]. 16 %u
long
long int
signed long
signed long int
Tip întreg semnat lung . Capabil să conțină cel puțin intervalul [-2.147.483.647, +2.147.483.647]. 32 %li sau %ld
unsigned long
unsigned long int
Tip întreg nesemnat lung . Capabil să conțină cel puțin intervalul [0, 4.294.967.295]. 32 %lu
long long
long long int
signed long long
signed long long int
Tip întreg semnat lung lung . Capabil să conțină cel puțin intervalul [-9.223.372.036.854.775.807, +9.223.372.036.854.775.807]. Specificat de la versiunea C99 a standardului. 64 %lli sau %lld
unsigned long long
unsigned long long int
Tip întreg lung nesemnat. Conține cel puțin intervalul [0, +18.446.744.073.709.551.615]. Specificat de la versiunea C99 a standardului. 64 %llu
float Tipul cu virgulă mobilă reală, denumit de obicei un tip cu virgulă mobilă de o singură precizie. Proprietăți reale nespecificate (cu excepția limitelor minime); cu toate acestea, pe majoritatea sistemelor, acesta este formatul IEEE 754 cu virgulă mobilă cu precizie simplă (32 biți). Acest format este cerut de anexa F opțională "IEC 60559 aritmetică în virgulă mobilă". Conversia din text:
double Tipul cu virgulă mobilă reală, denumit de obicei un tip cu virgulă mobilă de dublă precizie. Proprietăți reale nespecificate (cu excepția limitelor minime); cu toate acestea, pe majoritatea sistemelor, acesta este formatul IEEE 754 cu virgulă mobilă cu precizie dublă (64 biți). Acest format este cerut de anexa F opțională "IEC 60559 aritmetică în virgulă mobilă".
long double Tip real cu virgulă mobilă, de obicei mapat la un format numeric cu virgulă mobilă de precizie extinsă . Proprietăți reale nespecificate. Poate fi format în virgulă mobilă cu precizie extinsă x86 (80 de biți, dar de obicei 96 de biți sau 128 de biți în memorie cu octeți de umplere ), non-IEEE „ dublu-dublu ” (128 biți), IEEE 754 flotant cu precizie cvadruplă -format punct (128 biți), sau la fel ca dublu. Consultați articolul despre dubla lungă pentru detalii. %Lf %LF
%Lg %LG
%Le %LE
%La %LA

Mărimea reală a tipurilor de numere întregi variază în funcție de implementare. Standardul necesită doar relații de dimensiune între tipurile de date și dimensiunile minime pentru fiecare tip de date:

Cerințele de relație sunt că long longnu este mai mic decât long, care nu este mai mic decât int, care nu este mai mic decât short. Deoarece chardimensiunea este întotdeauna tipul minim de date acceptate, niciun alt tip de date (cu excepția câmpurilor de biți ) nu poate fi mai mic.

Dimensiunea minimă pentru chareste de 8 biți, dimensiunea minimă pentru shortși inteste de 16 biți, longdeoarece este de 32 de biți și long longtrebuie să conțină cel puțin 64 de biți.

Tipul inttrebuie să fie tipul întreg cu care procesorul țintă lucrează cel mai eficient. Acest lucru permite o mare flexibilitate: de exemplu, toate tipurile pot fi pe 64 de biți. Cu toate acestea, sunt cunoscute mai multe scheme de lățime întregi diferite (modele de date). Deoarece modelul de date definește modul în care comunică diferite programe, se utilizează un model de date uniform într-o anumită interfață de aplicație a sistemului de operare.

În practică, charare de obicei o dimensiune de 8 biți și shortare de obicei o dimensiune de 16 biți (la fel ca și omologii lor nesemnați). Acest lucru este valabil pentru platforme la fel de diverse precum SunOS  4 Unix din anii 90 , Microsoft MS-DOS , Linux modern și Microchip MCC18 pentru microcontrolere PIC încorporate pe 8 biți . POSIX necesită o chardimensiune de exact 8 biți.

Diferite reguli din standardul C fac unsigned charca tipul de bază utilizat pentru matrici să fie adecvat pentru stocarea obiectelor arbitrare fără câmp de biți: lipsa de biți de umplere și reprezentări trap, definiția reprezentării obiectelor și posibilitatea aliasării.

Mărimea reală și comportamentul tipurilor cu virgulă mobilă variază, de asemenea, în funcție de implementare. Singura garanție este că long doublenu este mai mic decât double, care nu este mai mic decât float. De obicei, sunt utilizate formatele pe virgulă mobilă IEEE 754 pe 32 și 64 de biți .

Standardul C99 include noi tipuri reale în virgulă mobilă float_tși double_t, definit în <math.h>. Ele corespund tipurilor utilizate pentru rezultatele intermediare ale expresiilor în virgulă mobilă atunci când FLT_EVAL_METHODeste 0, 1 sau 2. Aceste tipuri pot fi mai largi decât long double.

C99 a adăugat , de asemenea , complexe tipuri: float _Complex, double _Complex, long double _Complex.

Tipul boolean

C99 a adăugat un tip boolean (adevărat / fals) _Bool. În plus, <stdbool.h>antetul se definește boolca un alias convenabil pentru acest tip și oferă, de asemenea, macrocomenzi pentru trueși false. _Boolfuncționează similar cu un tip întreg normal, cu o singură excepție: orice alocări către un _Boolcare nu sunt 0 (fals) sunt stocate ca 1 (adevărat). Acest comportament există pentru a evita depășirile întregi în conversiile de îngustare implicită. De exemplu, în următorul cod:

unsigned char b = 256;

if (b) {
	/* do something */
}

Variabila se bevaluează la fals dacă unsigned charare o dimensiune de 8 biți. Acest lucru se datorează faptului că valoarea 256 nu se încadrează în tipul de date, ceea ce duce la utilizarea celor 8 biți inferiori ai acestuia, rezultând o valoare zero. Cu toate acestea, modificarea tipului face ca codul anterior să se comporte normal:

_Bool b = 256;

if (b) {
	/* do something */
}

Tipul _Bool asigură, de asemenea, că valorile adevărate se compară întotdeauna egale între ele:

_Bool a = 1, b = 2;

if (a == b) {
	/* do something */
}

Dimensiune și tipuri de diferențe ale indicatorului

Specificația limbajul C include typedef s size_tși ptrdiff_tpentru reprezentarea cantităților-memorie aferente. Dimensiunea lor este definită în funcție de capacitățile aritmetice ale procesorului țintă, nu de capacitățile de memorie, cum ar fi spațiul de adresă disponibil. Ambele tipuri sunt definite în <stddef.h>antet ( cstddefîn C ++).

size_teste un tip întreg nesemnat folosit pentru a reprezenta dimensiunea oricărui obiect (inclusiv matrici) în implementarea particulară. Operatorul sizeof produce o valoare de tip size_t. Dimensiunea maximă a size_teste furnizată prin SIZE_MAX, o constantă macro care este definită în antet ( antet în C ++). este garantat să aibă o lățime de cel puțin 16 biți. In plus, POSIX include , care este un tip întreg semnat de aceeași lățime ca și . <stdint.h>cstdintsize_tssize_tsize_t

ptrdiff_teste un tip întreg semnat utilizat pentru a reprezenta diferența dintre pointeri. Se garantează că este valabil numai împotriva pointerilor de același tip; scăderea pointerilor constând din diferite tipuri este definită de implementare.

Interfață cu proprietățile tipurilor de bază

Informațiile despre proprietățile reale, cum ar fi dimensiunea, tipurilor de bază aritmetice, sunt furnizate prin constante macro în două antete: <limits.h>antetul ( climitsantetul în C ++) definește macro-urile pentru tipurile întregi și <float.h>antetul ( cfloatantetul în C ++) definește macrocomenzile pentru tipurile cu virgulă mobilă . Valorile reale depind de implementare.

Proprietățile tipurilor întregi

  • CHAR_BIT - dimensiunea tipului de caractere în biți (cel puțin 8 biți)
  • SCHAR_MIN, SHRT_MIN, INT_MIN, LONG_MIN, LLONG_MIN(C99) - valoarea minimă posibilă a tipurilor semnate intregi: char semnat, semnat scurt, int semnat, semnat lung, semnat lung lung
  • SCHAR_MAX, SHRT_MAX, INT_MAX, LONG_MAX, LLONG_MAX(C99) - valoarea maximă posibilă a tipurilor semnate intregi: char semnat, semnat scurt, int semnat, semnat lung, semnat lung lung
  • UCHAR_MAX, USHRT_MAX, UINT_MAX, ULONG_MAX, ULLONG_MAX(C99) - valoarea maximă posibilă a tipurilor unsigned intregi: unsigned char, scurt, unsigned unsigned int, unsigned long, unsigned lung lung
  • CHAR_MIN - valoarea minimă posibilă a caracterului
  • CHAR_MAX - valoarea maximă posibilă a caracterului
  • MB_LEN_MAX - numărul maxim de octeți într-un caracter multibyte

Proprietățile tipurilor de virgulă mobilă

  • FLT_MIN, DBL_MIN, LDBL_MIN- minim normalizat valoare pozitivă de float, dublu, lung dublu respectiv
  • FLT_TRUE_MIN, DBL_TRUE_MIN, LDBL_TRUE_MIN(C11) - valoarea minimă pozitivă float, dublu, lung dublu respectiv
  • FLT_MAX, DBL_MAX, LDBL_MAX- valoarea maximă finită de float, dublu, lung dublu, respectiv
  • FLT_ROUNDS - modul de rotunjire pentru operații în virgulă mobilă
  • FLT_EVAL_METHOD (C99) - metodă de evaluare a expresiilor care implică diferite tipuri în virgulă mobilă
  • FLT_RADIX - raza exponentului în tipurile cu virgulă mobilă
  • FLT_DIG, DBL_DIG, LDBL_DIG- numărul de cifre zecimale , care pot fi reprezentate fără a pierde din precizie de float, dublu, lung dublu, respectiv
  • FLT_EPSILON, DBL_EPSILON, LDBL_EPSILON- diferența între 1.0 și următoarea valoare reprezentabile de float, dublu, lung dublu, respectiv
  • FLT_MANT_DIG, DBL_MANT_DIG, LDBL_MANT_DIG- numărul de FLT_RADIXcifre -base în virgulă flotantă significand pentru tipurile float, dublu, lung dublu, respectiv
  • FLT_MIN_EXP, DBL_MIN_EXP, LDBL_MIN_EXP- negativ minim întreg astfel încât FLT_RADIXridicat la o singură putere mai mică decât numărul respectiv este un float normalizat, dublu, lung dublu, respectiv
  • FLT_MIN_10_EXP, DBL_MIN_10_EXP, LDBL_MIN_10_EXP- negativ minim întreg , astfel încât 10 ridicat la acea putere este un float normalizat, dublu, lung dublu, respectiv
  • FLT_MAX_EXP, DBL_MAX_EXP, LDBL_MAX_EXP- pozitiv maxim întreg , astfel încât FLT_RADIXridicat la o singură putere mai mică decât numărul respectiv este un float normalizat, dublu, lung dublu, respectiv
  • FLT_MAX_10_EXP, DBL_MAX_10_EXP, LDBL_MAX_10_EXP- pozitiv maxim întreg , astfel încât 10 ridicat la acea putere este un float normalizat, dublu, lung dublu, respectiv
  • DECIMAL_DIG(C99) - numărul minim de cifre zecimale astfel încât orice număr al celui mai larg tip de virgulă mobilă acceptată să poată fi reprezentat în zecimal cu o precizie de DECIMAL_DIGcifre și citit înapoi în tipul virgulă mobilă originală fără a-i modifica valoarea. DECIMAL_DIGeste cel puțin 10.

Tipuri întregi cu lățime fixă

Standardul C99 include definiții ale mai multor noi tipuri întregi pentru a spori portabilitatea programelor. Tipurile întregi de bază deja disponibile au fost considerate insuficiente, deoarece dimensiunile lor reale sunt definite de implementare și pot varia în funcție de sisteme diferite. Noile tipuri sunt utile în special în mediile încorporate în care hardware-ul acceptă de obicei doar mai multe tipuri și care suportă variază între medii diferite. Toate tipurile noi sunt definite în <inttypes.h>antet ( cinttypesantet în C ++) și, de asemenea, sunt disponibile la <stdint.h>antet ( cstdintantet în C ++). Tipurile pot fi grupate în următoarele categorii:

  • Tipuri întregi Exact lățime care sunt garantate să aibă același număr n de biți din toate implementările. Inclus numai dacă este disponibil în implementare.
  • Tipuri întregi cel lățime care sunt garantate să fie cel mai mic tip disponibil în implementare, care are cel puțin specificat număr n de biți. Garantat pentru a fi specificat pentru cel puțin N = 8,16,32,64.
  • Cele mai rapide tipuri întregi , care sunt garantate pentru a fi cel mai rapid tip întreg disponibil în punerea în aplicare, care are cel puțin specificat numărul n de biți. Garantat pentru a fi specificat pentru cel puțin N = 8,16,32,64.
  • Tipuri întregi de pointer care sunt garantate pentru a putea ține un pointer. Inclus numai dacă este disponibil în implementare.
  • Tipuri întregi cu lățime maximă care sunt garantate a fi cel mai mare tip întreg din implementare.

Următorul tabel rezumă tipurile și interfața pentru a obține detaliile implementării ( n se referă la numărul de biți):

Categorie tip Tipuri semnate Tipuri nesemnate
Tip Valoare minimă Valoare maximă Tip Valoare minimă Valoare maximă
Lățime exactă intn_t INTn_MIN INTn_MAX uintn_t 0 UINTn_MAX
Lățimea minimă int_leastn_t INT_LEASTn_MIN INT_LEASTn_MAX uint_leastn_t 0 UINT_LEASTn_MAX
Cel mai rapid int_fastn_t INT_FASTn_MIN INT_FASTn_MAX uint_fastn_t 0 UINT_FASTn_MAX
Pointer intptr_t INTPTR_MIN INTPTR_MAX uintptr_t 0 UINTPTR_MAX
Lățimea maximă intmax_t INTMAX_MIN INTMAX_MAX uintmax_t 0 UINTMAX_MAX

Specificatori de format Printf și scanf

<inttypes.h>Antet ( cinttypesîn C ++) oferă caracteristici care sporesc funcționalitatea tipurilor definite în <stdint.h>antet. Acesta definește macrocomenzi pentru șiruri de format printf și specificatori de șiruri de format scanf corespunzătoare tipurilor definite <stdint.h>și mai multor funcții pentru lucrul cu tipurile intmax_tși uintmax_t. Acest antet a fost adăugat în C99 .

Șir de format Printf

Macrocomenzile sunt în format . Aici {fmt} definește formatarea de ieșire și este una dintre (zecimal), (hexazecimal), (octal), (nesemnat) și (întreg). {tip} definește tipul de argument și este unul dintre , , , , , unde corespunde numărului de biți în argument. PRI{fmt}{type}dxouinFASTnLEASTnPTRMAXn

Șir de format Scanf

Macrocomenzile sunt în format . Aici {fmt} definește formatarea de ieșire și este una dintre (zecimal), (hexazecimal), (octal), (nesemnat) și (întreg). {tip} definește tipul de argument și este unul dintre , , , , , unde corespunde numărului de biți în argument. SCN{fmt}{type}dxouinFASTnLEASTnPTRMAXn

Funcții

Tipuri suplimentare în virgulă mobilă

În mod similar cu tipurile întregi cu lățime fixă, ISO / IEC TS 18661 specifică tipurile cu virgulă mobilă pentru schimbul IEEE 754 și formate extinse în binar și zecimal:

  • _FloatN pentru formate de schimb binar;
  • _DecimalN pentru formatele de schimb zecimal;
  • _FloatNx pentru formate binare extinse;
  • _DecimalNx pentru formate extinse zecimale.

Structuri

Structurile agregează stocarea mai multor elemente de date, de tipuri de date potențial diferite, într-un bloc de memorie la care se face referire printr-o singură variabilă. Următorul exemplu declară tipul de date struct birthdaycare conține numele și ziua de naștere a unei persoane. Definiția structurii este urmată de o declarație a variabilei Johncare alocă stocarea necesară.

struct birthday {
	char name[20];
	int day;
	int month;
	int year;
};

struct birthday John;

Aspectul memoriei unei structuri este o problemă de implementare a limbajului pentru fiecare platformă, cu câteva restricții. Adresa de memorie a primului membru trebuie să fie aceeași cu adresa structurii în sine. Structurile pot fi inițializate sau atribuite folosirii literelor compuse. O funcție poate returna direct o structură, deși acest lucru nu este adesea eficient în timpul rulării. De la C99 , o structură se poate termina, de asemenea, cu un membru de matrice flexibil .

O structură care conține un pointer către o structură de tip propriu este utilizată în mod obișnuit pentru a construi structuri de date legate :

struct node {
	int val;
	struct node *next;
};

Matrice

Pentru fiecare tip T, cu excepția tipurilor de funcții și de goluri , există tipurile „matrice de Nelemente de tip T . O matrice este o colecție de valori, toate de același tip, stocate contigu în memorie. O matrice de dimensiuni Neste indexată de numere întregi de la 0până la inclusiv N−1. Iată un scurt exemplu:

int cat[10];  // array of 10 elements, each of type int

Tablourile pot fi inițializate cu un inițializator compus, dar nu alocate. Tablourile sunt transmise funcțiilor trecând un pointer la primul element. Tablourile multidimensionale sunt definite ca "matrice de matrice ..." și toate, cu excepția dimensiunii exterioare, trebuie să aibă dimensiunea constantă a timpului de compilare:

int a[10][8];  // array of 10 elements, each of type 'array of 8 int elements'

Indicatori

Fiecare tip de date Tare un pointer deT tip corespunzător . Un indicator este un tip de date care conține adresa unei locații de stocare a unei variabile de un anumit tip. Acestea sunt declarate cu declaratorul de tip asterisc ( *) urmând tipul de stocare de bază și precedând numele variabilei. Spațiul alb înainte sau după asterisc este opțional.

char *square;
long *circle;
int *oval;

Pointerii pot fi, de asemenea, declarați pentru tipurile de date ale pointerului, creând astfel mai multe pointeri indirecte, cum ar fi char ** și int *** , inclusiv pointeri către tipuri de matrice. Acestea din urmă sunt mai puțin frecvente decât o serie de indicatori, iar sintaxa lor poate fi confuză:

char *pc[10];   // array of 10 elements of 'pointer to char'
char (*pa)[10]; // pointer to a 10-element array of char

Elementul pcnecesită zece blocuri de memorie de dimensiunea indicatoruluichar (de obicei 40 sau 80 de octeți pe platformele comune), dar elementul paeste doar un indicator (dimensiunea 4 sau 8 octeți), iar datele la care se referă sunt o matrice de zece octeți ( ). sizeof *pa == 10

Sindicatele

Un tip de uniune este o construcție specială care permite accesul la același bloc de memorie utilizând o gamă de descrieri de tipuri diferite. De exemplu, o uniune de tipuri de date poate fi declarată pentru a permite citirea acelorași date fie ca un număr întreg, ca float sau orice alt tip declarat de utilizator:

union {
	int i;
	float f;
	struct {
		unsigned int u;
		double d;
	} s;
} u;

Dimensiunea totală a ueste mărimea lui u.s- care se întâmplă să fie suma mărimilor lui u.s.uși u.s.d- deoarece seste mai mare decât ambele iși f. Atunci când atribuiți ceva u.i, unele părți din u.fpot fi păstrate dacă u.isunt mai mici decât u.f.

Citirea de la un membru al sindicatului nu este la fel ca castingul, deoarece valoarea membrului nu este convertită, ci doar citită.

Indicații funcționale

Indicatorii de funcții permit referirea funcțiilor cu o anumită semnătură. De exemplu, pentru a stoca adresa funcției standard absîn variabilă my_int_f:

int (*my_int_f)(int) = &abs;
// the & operator can be omitted, but makes clear that the "address of" abs is used here

Indicatorii de funcție sunt invocați prin nume la fel ca apelurile de funcții normale. Pointerii de funcții sunt separați de pointeri și pointeri de gol .

Tipul calificărilor

Tipurile menționate mai sus pot fi caracterizate în continuare prin calificative de tip , rezultând un tip calificat . Începând cu 2014 și C11 , există patru calificative de tip în standardul C: const( C89 ), volatile( C89 ), restrict( C99 ) și _Atomic( C11 ) - acesta din urmă are un nume privat pentru a evita confruntarea cu numele utilizatorilor, dar numele mai obișnuit atomicpoate să fie utilizat dacă <stdatomic.h>antetul este inclus. Dintre acestea, consteste de departe cea mai cunoscută și cea mai utilizată, care apare în biblioteca standard și întâlnită în orice utilizare semnificativă a limbajului C, care trebuie să satisfacă corectitudinea constanței . Celelalte calificative sunt utilizate pentru programarea la nivel scăzut și, deși sunt utilizate pe scară largă acolo, sunt rareori folosite de programatorii tipici.

Vezi si

Referințe