Types de données C - C data types

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 %hhipour 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 %hhupour 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 longn'est pas plus petit que long, qui n'est pas plus petit que int, qui n'est pas plus petit que short. Comme charla 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 charest de 8 bits, la taille minimale pour shortet intest de 16 bits, car longelle est de 32 bits et long longdoit contenir au moins 64 bits.

Le type intdoit ê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, charsa taille est généralement de 8 bits et sa taille de short16 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 charune taille d'exactement 8 bits.

Diverses règles de la norme C rendent unsigned charle 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 doublen'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_tet 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_METHODvaut 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 boolcomme un alias pratique pour ce type et fournit également des macros pour trueet false. _Boolfonctionne de manière similaire à un type entier normal, à une exception près : toutes les affectations à a _Boolqui 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 chara 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_tet ptrdiff_tpour 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 ( cstddefen C++).

size_test 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_test 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>cstdintsize_tssize_tsize_t

ptrdiff_test 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- climitstête en C++) définit les macros pour les types entiers et l'en- <float.h>tête ( en- cfloattê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_EPSILONdiffé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 de FLT_RADIXchiffres 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 que FLT_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 que FLT_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 de DECIMAL_DIGchiffres et relu dans le type à virgule flottante d'origine sans changer sa valeur. DECIMAL_DIGest 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- cinttypestête en C++) et sont également disponibles dans l'en- <stdint.h>tête ( en- cstdinttê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 ( cinttypesen 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_tet 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}dxouinFASTnLEASTnPTRMAXn

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}dxouinFASTnLEASTnPTRMAXn

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 birthdayqui contient le nom et l'anniversaire d'une personne. La définition de la structure est suivie d'une déclaration de la variable Johnqui 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 Nest indexé par des entiers allant 0jusqu'à 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 Ta 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 pcné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 pan'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 uest la taille de u.s– qui se trouve être la somme des tailles de u.s.uet u.s.d– puisque sest plus grande que les deux iet f. Lors de l'affectation de quelque chose à u.i, certaines parties de u.fpeuvent être conservées si u.iest 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 absdans 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 atomicpeut être utilisé si l'en- <stdatomic.h>tête est inclus. Parmi ceux-ci, constest 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.

Voir également

Les références