Types de données C - C data types
bibliothèque standard C |
---|
Thèmes généraux |
En-têtes divers |
|
Dans le langage de programmation C , les types de données constituent la sémantique et les caractéristiques de stockage des éléments de données. Ils sont exprimés dans la syntaxe du langage sous forme de déclarations d' emplacements mémoire ou de variables . Les types de données déterminent également les types d'opérations ou les méthodes de traitement des éléments de données.
Le langage C fournit des types arithmétiques de base, tels que des types entiers et des nombres réels , et une syntaxe pour créer des types de tableaux et composés. Les en-têtes de la bibliothèque standard C , à utiliser via les directives include , contiennent des définitions de types de support, qui ont des propriétés supplémentaires, telles que fournir un stockage avec une taille exacte, indépendante de l'implémentation du langage sur des plates-formes matérielles spécifiques.
Types de base
Types principaux
Le langage C fournit les quatre spécificateurs de type arithmétique de base char , int , float et double , et les modificateurs signé , unsigned , short et long . Le tableau suivant répertorie les combinaisons autorisées pour spécifier un grand ensemble de déclarations spécifiques à la taille de stockage.
Taper | Explication | Taille minimale (bits) | Spécificateur de format |
---|---|---|---|
char |
Plus petite unité adressable de la machine pouvant contenir un jeu de caractères de base. C'est un type entier . Le type réel peut être signé ou non signé. Il contient des bits CHAR_BIT. | 8 |
%c
|
signed char |
De la même taille que char , mais garantie d'être signée. Capable de contenir au moins la plage [−127, +127]. | 8 |
%c (ou %hhi pour sortie numérique)
|
unsigned char |
De la même taille que char , mais garanti non signé. Contient au moins la plage [0, 255]. | 8 |
%c (ou %hhu pour sortie numérique)
|
short short int signed short signed short int
|
Type d'entier court signé. Capable de contenir au moins la plage [−32 767, +32 767]. | 16 |
%hi ou %hd
|
unsigned short unsigned short int
|
Type entier court non signé. Contient au moins la plage [0, 65 535]. | 16 |
%hu
|
int signed signed int
|
Type entier signé de base. Capable de contenir au moins la plage [−32 767, +32 767]. | 16 |
%i ou %d
|
unsigned unsigned int
|
Type entier non signé de base. Contient au moins la plage [0, 65 535]. | 16 |
%u
|
long long int signed long signed long int
|
Type entier signé long . Capable de contenir au moins la gamme [-2 147 483 647, +2 147 483 647]. | 32 |
%li ou %ld
|
unsigned long unsigned long int
|
Type entier long non signé. Capable de contenir au moins la plage [0, 4 294 967 295]. | 32 |
%lu
|
long long long long int signed long long signed long long int
|
Type entier long long signé. Capable de contenir au moins la gamme [-9 223 372 036 854 775 807, +9 223 372 036 854 775 807]. Spécifié depuis la version C99 de la norme. | 64 |
%lli ou %lld
|
unsigned long long unsigned long long int
|
Type entier long long non signé. Contient au moins la plage [0, +18 446 744 073 709 551 615]. Spécifié depuis la version C99 de la norme. | 64 |
%llu
|
float |
Type à virgule flottante réel, généralement appelé type à virgule flottante simple précision. Propriétés réelles non spécifiées (sauf limites minimales) ; cependant, sur la plupart des systèmes, il s'agit du format à virgule flottante binaire simple précision IEEE 754 (32 bits). Ce format est requis par l'annexe F facultative "arithmétique à virgule flottante CEI 60559". | Conversion à partir de texte : | |
double |
Type à virgule flottante réel, généralement appelé type à virgule flottante double précision. Propriétés réelles non spécifiées (sauf limites minimales) ; cependant, sur la plupart des systèmes, il s'agit du format à virgule flottante binaire double précision IEEE 754 (64 bits). Ce format est requis par l'annexe F facultative "CEI 60559 arithmétique à virgule flottante". | ||
long double |
Type à virgule flottante réel, généralement mappé à un format de nombre à virgule flottante à précision étendue . Propriétés réelles non spécifiées. Il peut s'agir du format à virgule flottante à précision étendue x86 (80 bits, mais généralement de 96 bits ou de 128 bits en mémoire avec des octets de remplissage ), du " double-double " non-IEEE (128 bits), du flottant à quadruple précision IEEE 754 format -point (128 bits), ou le même que double. Voir l'article sur le double long pour plus de détails. |
%Lf %LF %Lg %LG %Le %LE %La %LA
|
La taille réelle des types entiers varie selon l'implémentation. La norme n'exige que des relations de taille entre les types de données et des tailles minimales pour chaque type de données :
Les exigences de la relation sont que le long long
n'est pas plus petit que long
, qui n'est pas plus petit que int
, qui n'est pas plus petit que short
. Comme char
la taille de est toujours le type de données minimum pris en charge, aucun autre type de données (à l'exception des champs de bits ) ne peut être plus petit.
La taille minimale pour char
est de 8 bits, la taille minimale pour short
et int
est de 16 bits, car long
elle est de 32 bits et long long
doit contenir au moins 64 bits.
Le type int
doit être le type entier avec lequel le processeur cible travaille le plus efficacement. Cela permet une grande flexibilité : par exemple, tous les types peuvent être en 64 bits. Cependant, plusieurs schémas de largeur entière différents (modèles de données) sont populaires. Étant donné que le modèle de données définit la façon dont différents programmes communiquent, un modèle de données uniforme est utilisé au sein d'une interface d'application de système d'exploitation donnée.
En pratique, char
sa taille est généralement de 8 bits et sa taille de short
16 bits (comme le sont leurs homologues non signés). Cela est vrai pour des plates-formes aussi diverses que SunOS 4 Unix des années 1990 , Microsoft MS-DOS , Linux moderne et Microchip MCC18 pour les microcontrôleurs PIC 8 bits intégrés . POSIX nécessite char
une taille d'exactement 8 bits.
Diverses règles de la norme C rendent unsigned char
le type de base utilisé pour les tableaux approprié pour stocker des objets arbitraires non-bit-field : son absence de bits de remplissage et de représentations de piège, la définition de la représentation d'objet et la possibilité d'alias.
La taille et le comportement réels des types à virgule flottante varient également selon l'implémentation. La seule garantie est que long double
n'est pas plus petit que double
, qui n'est pas plus petit que float
. Généralement, les formats binaires à virgule flottante IEEE 754 32 bits et 64 bits sont utilisés.
La norme C99 inclut de nouveaux types réels à virgule flottante float_t
et double_t
, définis dans <math.h>
. Ils correspondent aux types utilisés pour les résultats intermédiaires des expressions à virgule flottante lorsque FLT_EVAL_METHOD
vaut 0, 1 ou 2. Ces types peuvent être plus larges que long double
.
C99 a également ajouté des types complexes : float _Complex
, double _Complex
, long double _Complex
.
Type booléen
C99 a ajouté un type booléen (vrai/faux) _Bool
. De plus, l'en- <stdbool.h>
tête définit bool
comme un alias pratique pour ce type et fournit également des macros pour true
et false
. _Bool
fonctionne de manière similaire à un type entier normal, à une exception près : toutes les affectations à a _Bool
qui ne sont pas 0 (faux) sont stockées comme 1 (vrai). Ce comportement existe pour éviter les débordements d'entiers dans les conversions restrictives implicites. Par exemple, dans le code suivant :
unsigned char b = 256;
if (b) {
/* do something */
}
La variable est b
évaluée à faux si elle unsigned char
a une taille de 8 bits. En effet, la valeur 256 ne correspond pas au type de données, ce qui entraîne l'utilisation des 8 bits inférieurs, ce qui entraîne une valeur nulle. Cependant, en changeant le type, le code précédent se comporte normalement :
_Bool b = 256;
if (b) {
/* do something */
}
Le type _Bool garantit également que les valeurs vraies se comparent toujours égales :
_Bool a = 1, b = 2;
if (a == b) {
/* do something */
}
Types de différence de taille et de pointeur
La spécification du langage C inclut les typedef s size_t
et ptrdiff_t
pour représenter les quantités liées à la mémoire. Leur taille est définie en fonction des capacités arithmétiques du processeur cible, et non des capacités de la mémoire, telles que l'espace d'adressage disponible. Ces deux types sont définis dans l'en- <stddef.h>
tête ( cstddef
en C++).
size_t
est un type entier non signé utilisé pour représenter la taille de tout objet (y compris les tableaux) dans l'implémentation particulière. L'opérateur sizeof renvoie une valeur du type size_t
. La taille maximale de size_t
est fournie via SIZE_MAX
, une macro constante qui est définie dans l'en- tête ( en- tête en C++). est garanti d'au moins 16 bits de large. De plus, POSIX inclut , qui est un type entier signé de la même largeur que .
<stdint.h>
cstdint
size_t
ssize_t
size_t
ptrdiff_t
est un type entier signé utilisé pour représenter la différence entre les pointeurs. Il est garanti qu'il n'est valide que contre des pointeurs du même type ; la soustraction de pointeurs constitués de différents types est définie par l'implémentation.
Interface vers les propriétés des types de base
Les informations sur les propriétés réelles, telles que la taille, des types arithmétiques de base, sont fournies via des constantes de macro dans deux en-têtes : l'en- <limits.h>
tête ( en- climits
tête en C++) définit les macros pour les types entiers et l'en- <float.h>
tête ( en- cfloat
tête en C++) définit les macros pour les types à virgule flottante . Les valeurs réelles dépendent de l'implémentation.
Propriétés des types entiers
-
CHAR_BIT
– taille du type char en bits (au moins 8 bits) -
SCHAR_MIN
,SHRT_MIN
,INT_MIN
,LONG_MIN
,LLONG_MIN
(C99) – valeur minimale possible des types d'entiers signés : char signé, signé court, signé int, signé long, signé long long -
SCHAR_MAX
,SHRT_MAX
,INT_MAX
,LONG_MAX
,LLONG_MAX
(C99) – valeur maximale possible des types d'entiers signés : char signé, signé court, signé int, signé long, signé long long -
UCHAR_MAX
,USHRT_MAX
,UINT_MAX
,ULONG_MAX
,ULLONG_MAX
(C99) – valeur maximale possible des types entiers non signés : unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long -
CHAR_MIN
– valeur minimale possible de char -
CHAR_MAX
– valeur maximale possible de char -
MB_LEN_MAX
– nombre maximum d'octets dans un caractère multi-octets
Propriétés des types à virgule flottante
-
FLT_MIN
,DBL_MIN
,LDBL_MIN
– valeur positive normalisée minimale de float, double, long double respectivement -
FLT_TRUE_MIN
,DBL_TRUE_MIN
,LDBL_TRUE_MIN
(C11) – valeur positive minimale de float, double, long double respectivement -
FLT_MAX
,DBL_MAX
,LDBL_MAX
– valeur finie maximale de float, double, long double, respectivement -
FLT_ROUNDS
– mode d'arrondi pour les opérations à virgule flottante -
FLT_EVAL_METHOD
(C99) – méthode d'évaluation des expressions impliquant différents types à virgule flottante -
FLT_RADIX
– base de l'exposant dans les types à virgule flottante -
FLT_DIG
,DBL_DIG
,LDBL_DIG
– nombre de chiffres décimaux pouvant être représentés sans perte de précision par float, double, long double, respectivement -
FLT_EPSILON
,DBL_EPSILON
,LDBL_EPSILON
– différence entre 1,0 et la prochaine valeur représentable de float, double, long double, respectivement -
FLT_MANT_DIG
,DBL_MANT_DIG
,LDBL_MANT_DIG
– nombre deFLT_RADIX
chiffres de base dans la mantisse à virgule flottante pour les types float, double, long double, respectivement -
FLT_MIN_EXP
,DBL_MIN_EXP
,LDBL_MIN_EXP
– nombre entier négatif minimum tel queFLT_RADIX
élevé à une puissance inférieure à ce nombre est un flottant normalisé, double, long double, respectivement -
FLT_MIN_10_EXP
,DBL_MIN_10_EXP
,LDBL_MIN_10_EXP
– nombre entier négatif minimum tel que 10 élevé à cette puissance soit un flottant normalisé, double, long double, respectivement -
FLT_MAX_EXP
,DBL_MAX_EXP
,LDBL_MAX_EXP
– nombre entier positif maximum tel queFLT_RADIX
élevé à une puissance inférieure à ce nombre est un float normalisé, double, long double, respectivement -
FLT_MAX_10_EXP
,DBL_MAX_10_EXP
,LDBL_MAX_10_EXP
– entier positif maximum tel que 10 élevé à cette puissance est un flottant normalisé, double, long double, respectivement -
DECIMAL_DIG
(C99) – nombre minimum de chiffres décimaux tel que n'importe quel nombre du type à virgule flottante le plus large pris en charge peut être représenté en décimal avec une précision deDECIMAL_DIG
chiffres et relu dans le type à virgule flottante d'origine sans changer sa valeur.DECIMAL_DIG
est d'au moins 10.
Types entiers à largeur fixe
La norme C99 inclut des définitions de plusieurs nouveaux types d'entiers pour améliorer la portabilité des programmes. Les types entiers de base déjà disponibles ont été jugés insuffisants, car leurs tailles réelles sont définies par la mise en œuvre et peuvent varier d'un système à l'autre. Les nouveaux types sont particulièrement utiles dans les environnements embarqués où le matériel ne prend généralement en charge que plusieurs types et cette prise en charge varie selon les différents environnements. Tous les nouveaux types sont définis dans l'en- <inttypes.h>
tête ( en- cinttypes
tête en C++) et sont également disponibles dans l'en- <stdint.h>
tête ( en- cstdint
tête en C++). Les types peuvent être regroupés dans les catégories suivantes :
- Types entiers de largeur exacte qui sont garantis d'avoir le même nombre n de bits dans toutes les implémentations. Inclus uniquement s'il est disponible dans l'implémentation.
- Types entiers de moindre largeur qui sont garantis être le plus petit type disponible dans l'implémentation, qui a au moins un nombre spécifié de bits n . Garanti à être spécifié pour au moins N=8,16,32,64.
- Meilleurs types d'entiers qui sont garantis d'être le type entier le plus rapide dans la mise en œuvre, qui a au moins certain nombre n de bits. Garanti à être spécifié pour au moins N=8,16,32,64.
- Types d'entiers de pointeur dont la capacité à contenir un pointeur est garantie. Inclus uniquement s'il est disponible dans l'implémentation.
- Types d'entiers de largeur maximale qui sont garantis comme étant le type d'entier le plus grand dans l'implémentation.
Le tableau suivant résume les types et l'interface pour acquérir les détails d'implémentation ( n fait référence au nombre de bits) :
Type de catégorie | Types signés | Types non signés | ||||
---|---|---|---|---|---|---|
Taper | Valeur minimum | Valeur maximum | Taper | Valeur minimum | Valeur maximum | |
Largeur exacte | intn_t |
INTn_MIN |
INTn_MAX
|
uintn_t |
0 |
UINTn_MAX
|
Largeur minimale | int_leastn_t |
INT_LEASTn_MIN |
INT_LEASTn_MAX
|
uint_leastn_t |
0 |
UINT_LEASTn_MAX
|
Le plus rapide | int_fastn_t |
INT_FASTn_MIN |
INT_FASTn_MAX
|
uint_fastn_t |
0 |
UINT_FASTn_MAX
|
Aiguille | intptr_t |
INTPTR_MIN |
INTPTR_MAX
|
uintptr_t |
0 |
UINTPTR_MAX
|
Largeur maximale | intmax_t |
INTMAX_MIN |
INTMAX_MAX
|
uintmax_t |
0 |
UINTMAX_MAX
|
Spécificateurs de format printf et scanf
L'en- <inttypes.h>
tête ( cinttypes
en C++) fournit des fonctionnalités qui améliorent la fonctionnalité des types définis dans l'en- <stdint.h>
tête. Il définit des macros pour les spécificateurs de chaîne de format printf et de chaîne de format scanf correspondant aux types définis dans <stdint.h>
et plusieurs fonctions pour travailler avec les types intmax_t
et uintmax_t
. Cet en-tête a été ajouté en C99 .
- Chaîne de format printf
Les macros sont au format . Ici, {fmt} définit le formatage de sortie et est l'un des (décimal), (hexadécimal), (octal), (non signé) et (entier). {type} définit le type de l'argument et est l'un des , , , , , où correspond au nombre de bits dans l'argument.
PRI{fmt}{type}
d
x
o
u
i
n
FASTn
LEASTn
PTR
MAX
n
- Chaîne de formatage Scanf
Les macros sont au format . Ici, {fmt} définit le formatage de sortie et est l'un des (décimal), (hexadécimal), (octal), (non signé) et (entier). {type} définit le type de l'argument et est l'un des , , , , , où correspond au nombre de bits dans l'argument.
SCN{fmt}{type}
d
x
o
u
i
n
FASTn
LEASTn
PTR
MAX
n
- Les fonctions
Types à virgule flottante supplémentaires
Comme pour les types entiers à largeur fixe, ISO/IEC TS 18661 spécifie les types à virgule flottante pour l'échange IEEE 754 et les formats étendus en binaire et décimal :
-
_FloatN
pour les formats d'échange binaires ; -
_DecimalN
pour les formats d'échange décimaux ; -
_FloatNx
pour les formats binaires étendus ; -
_DecimalNx
pour les formats décimaux étendus.
Structures
Les structures regroupent le stockage de plusieurs éléments de données, de types de données potentiellement différents, dans un bloc mémoire référencé par une seule variable. L'exemple suivant déclare le type de données struct birthday
qui contient le nom et l'anniversaire d'une personne. La définition de la structure est suivie d'une déclaration de la variable John
qui alloue la mémoire nécessaire.
struct birthday {
char name[20];
int day;
int month;
int year;
};
struct birthday John;
L'agencement de la mémoire d'une structure est un problème d'implémentation du langage pour chaque plate-forme, avec quelques restrictions. L'adresse mémoire du premier membre doit être la même que l'adresse de la structure elle-même. Les structures peuvent être initialisées ou affectées à l'aide de littéraux composés. Une fonction peut renvoyer directement une structure, bien que cela ne soit souvent pas efficace au moment de l'exécution. Depuis C99 , une structure peut également se terminer par un membre de tableau flexible .
Une structure contenant un pointeur vers une structure de son propre type est couramment utilisée pour construire des structures de données liées :
struct node {
int val;
struct node *next;
};
Tableaux
Pour chaque type T
, à l'exception des types void et function, il existe les types "tableau d' N
éléments de type T
" . Un tableau est un ensemble de valeurs, toutes du même type, stockées de manière contiguë en mémoire. Un tableau de taille N
est indexé par des entiers allant 0
jusqu'à et y compris N−1
. Voici un bref exemple :
int cat[10]; // array of 10 elements, each of type int
Les tableaux peuvent être initialisés avec un initialiseur composé, mais non attribués. Les tableaux sont passés aux fonctions en passant un pointeur sur le premier élément. Les tableaux multidimensionnels sont définis comme « tableau de tableaux … » , et tous, à l'exception de la dimension la plus externe, doivent avoir une taille constante au moment de la compilation :
int a[10][8]; // array of 10 elements, each of type 'array of 8 int elements'
Pointeurs
Chaque type de données T
a un pointeur deT
type correspondant vers . Un pointeur est un type de données qui contient l'adresse d'un emplacement de stockage d'une variable d'un type particulier. Ils sont déclarés avec le *
déclarateur de type astérisque ( ) suivant le type de stockage de base et précédant le nom de la variable. Les espaces avant ou après l'astérisque sont facultatifs.
char *square;
long *circle;
int *oval;
Des pointeurs peuvent également être déclarés pour les types de données de pointeur, créant ainsi plusieurs pointeurs indirects, tels que char ** et int *** , y compris des pointeurs vers des types de tableau. Ces derniers sont moins courants qu'un tableau de pointeurs, et leur syntaxe peut prêter à confusion :
char *pc[10]; // array of 10 elements of 'pointer to char'
char (*pa)[10]; // pointer to a 10-element array of char
L'élément pc
nécessite dix blocs de mémoire de la taille du pointeurchar
(généralement 40 ou 80 octets sur les plates-formes courantes), mais l'élément pa
n'est qu'un pointeur (taille 4 ou 8 octets) et les données auxquelles il se réfère sont un tableau de dix octets ( ).
sizeof *pa == 10
Syndicats
Un type d'union est une construction spéciale qui permet d'accéder au même bloc de mémoire en utilisant un choix de descriptions de types différentes. Par exemple, une union de types de données peut être déclarée pour permettre la lecture des mêmes données sous forme d'entier, de flottant ou de tout autre type déclaré par l'utilisateur :
union {
int i;
float f;
struct {
unsigned int u;
double d;
} s;
} u;
La taille totale de u
est la taille de u.s
– qui se trouve être la somme des tailles de u.s.u
et u.s.d
– puisque s
est plus grande que les deux i
et f
. Lors de l'affectation de quelque chose à u.i
, certaines parties de u.f
peuvent être conservées si u.i
est plus petit que u.f
.
La lecture d'un membre de l'union n'est pas la même chose que le casting puisque la valeur du membre n'est pas convertie, mais simplement lue.
Pointeurs de fonction
Les pointeurs de fonction permettent de référencer des fonctions avec une signature particulière. Par exemple, pour stocker l'adresse de la fonction standard abs
dans la variable 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
Les pointeurs de fonction sont appelés par leur nom, tout comme les appels de fonction normaux. Les pointeurs de fonction sont distincts des pointeurs et des pointeurs void .
Qualificatifs de type
Les types susmentionnés peuvent être caractérisés en outre par des qualificatifs de type , ce qui donne un type qualifié . Depuis 2014 et C11 , il existe quatre qualificatifs de type dans la norme C : const
( C89 ), volatile
( C89 ), restrict
( C99 ) et _Atomic
( C11 ) - ce dernier a un nom privé pour éviter d'entrer en conflit avec les noms d'utilisateur, mais le nom plus ordinaire atomic
peut être utilisé si l'en- <stdatomic.h>
tête est inclus. Parmi ceux-ci, const
est de loin le plus connu et le plus utilisé, apparaissant dans la bibliothèque standard et rencontré dans toute utilisation significative du langage C, qui doit satisfaire const-correctness . Les autres qualificatifs sont utilisés pour la programmation de bas niveau, et bien que largement utilisés là-bas, sont rarement utilisés par les programmeurs typiques.