sizeof
Dans les langages de programmation C et C++, l'opérateur unaire sizeof[1] donne la taille en bytes de son opérande. L'opérande peut être un spécificateur de type ou une expression.
Type |
Opérateur unaire, C programming language keyword (d) |
---|---|
Partie de |
Description détaillée
modifierLes types primitifs tels que char, int ou void* (non exhaustif) ont une taille dépendante du système pour lequel le code est compilé, elle est généralement documentée pour chaque système.
Les structures, quant à elles, contiennent souvent plusieurs champs de types différents, la taille totale dépend donc de l'alignement de ses champs ainsi que de son alignement total. La taille retournée peut alors compter un rembourrage (ou padding en anglais) après le dernier champ, cette taille peut alors servir pour connaitre l'intervalle en bytes entre les éléments d'un tableau du type donné. Les structures et classes vides ont une taille de 1 byte.
Une exception à cette règle sont les structures packed, qui ne nécessite pas d'alignement (cela signifie qu'il est forcé à 1), dans ce cas la taille est la somme de la taille de tous les champs.
À cet opérateur peut être donné une expression, auquel cas sizeof rend la taille du type résultant de l'expression.
Lorsqu'un tableau est passé par type ou expression, l'opérateur renvoie la taille totale de tableau en bytes.
Les valeurs retournées par cet opérande sont de type size_t (un type entier non signé défini par l'entête standard <stddef.h>).
L'exemple suivant résume les valeurs retournées dans certains cas communs :
int i = 21;
size_t int_size = sizeof(int); // = 4.
// Ici, les paranthèses sont nécessaires pour lever de potentielles ambiguités.
size_t i_size = sizeof i; // = 4, car i de type "int".
// On remarquera l'absence de paranthèses, car sizeof est un opérateur.
int table[10];
size_t int_table_size = sizeof(int[10]); // = 40 = 10 * sizeof(int)
size_t table_size = sizeof table; // = 40, car de type int[10]
struct empty {};
size_t empty_size = sizeof(struct empty); // = 1
struct padded {
char char0;
// Rembourrage de 3 bytes pour aligner "number" sur 4 bytes.
int number;
// Aucun rembourrage, puisque le type "char" ne nécessite pas d'alignement (alignement = 1).
char char1;
// Rembourrage de fin de 3 bytes.
};
size_t padded_size = sizeof(struct padded); // = 12
// On peut réorganiser les champs de la structure précédente afin d'observer l'impact de l'alignement sur la taille d'une structure :
struct padded_better {
char char0;
char char1;
// Rembourrage de 2 bytes.
int number;
};
size_t padded_better_size = sizeof(struct padded_better); // = 8
Utilité
modifierDans plusieurs programmes, il est utile de connaitre la taille d'un type de données. Bien que pour n'importe quelle implémentation de C ou C++, la taille d'un type de données particulier soit constant, les tailles de mêmes types primitifs en C et en C++ sont définies par l'implémentation. C'est important lors de l'attribution d'un bloc de mémoire d'une taille appropriée.
int *pointeur;
pointeur = (int *) malloc(10 * sizeof (int));
Dans cet exemple, malloc alloue de la mémoire et retourne un pointeur vers le bloc mémoire. La taille du bloc alloué est égale au nombre de bytes pour un seul objet de type int
multiplié par 10, assurant assez d'espace pour 10 entiers.
On ne peut généralement pas présumer de la taille de tous types de données. Par exemple, même si la plupart des implémentations de C et C++ sur des systèmes 32-bits allouent 4 octets pour le type int, cette taille peut changer quand le code est porté vers un système différent. L'exception est le type char, dont la taille est toujours 1 dans toutes les implémentations de C. De plus, il est fréquemment difficile de prédire la taille de types composés comme les struct et les union, en raison du rembourrage. L'utilisation de sizeof permet la portabilité du code.