Dans plusieurs exemples C++, je vois une utilisation du type size_t
où j'aurais utilisé un simple int
. Quelle est la différence et pourquoi size_t
ça pourrait être mieux?
Les fichiers d'en-tête stdlib.h et stddef.h définissent un type de données appelé size_t utilisé pour représenter la taille d'un objet. Les fonctions de bibliothèque prenant des tailles s'attendent à ce qu'elles soient de type size_t et l'opérateur sizeof est évalué à size_t.
Le type réel de size_t dépend de la plate-forme; une erreur courante est de supposer que size_t est identique à unsigned int, ce qui peut entraîner des erreurs de programmation, en particulier lorsque les architectures 64 bits deviennent plus courantes.
Vérifiez également Pourquoi size_t est important
size_t est le type utilisé pour représenter les tailles (comme son nom l'indique). Sa plate-forme (et même potentiellement sa mise en œuvre) dépend, et ne devrait être utilisée qu’à cette fin. Évidemment, représentant une taille, size_t n'est pas signé. De nombreuses fonctions stdlib, y compris malloc, sizeof et diverses opérations sur les chaînes, utilisent size_t comme type de données.
Un int est signé par défaut et, même si sa taille dépend également de la plate-forme, il sera fixe à 32 bits sur la plupart des machines modernes (et bien que size_t soit 64 bits sur une architecture 64 bits, int restera 32 bits sur ces architectures).
Pour résumer: utilisez size_t pour représenter la taille d'un objet et int (ou long) dans les autres cas.
C'est parce que size_t peut être autre chose qu'un int (peut-être une struct). L'idée est de séparer son travail du type sous-jacent.
Le size_t
type est défini comme le type intégral non signé de l'opérateur sizeof
. Dans le monde réel, vous verrez souvent int
défini comme 32 bits (pour la compatibilité ascendante) mais size_t
défini comme 64 bits (vous pouvez donc déclarer des tableaux et des structures supérieurs à 4 GiB)) sur les plates-formes 64 bits. Si long int
est aussi 64 bits, on appelle cela la convention LP64; si long int
est 32 bits mais long long int
et les pointeurs sont en 64 bits, c’est LLP64. Vous pouvez également obtenir l’inverse, un programme qui utilise des instructions 64 bits pour la vitesse, mais des pointeurs 32 bits pour économiser de la mémoire. De plus, int
est signé et size_t
n'est pas signé.
Il y avait historiquement un certain nombre d'autres plates-formes où les adresses étaient plus larges ou plus courtes que la taille native de int
. En fait, dans les années 70 et au début des années 80, cela était plus courant qu'ailleurs: tous les micro-ordinateurs 8 bits populaires avaient des registres 8 bits et des adresses 16 bits, et la transition entre 16 et 32 bits produisait également de nombreuses machines qui avaient des adresses plus larges que leurs registres. Je vois encore parfois des questions sur Borland Turbo C pour MS-DOS, dont le mode Mémoire énorme comportait des adresses 20 bits stockées en 32 bits sur un processeur 16 bits (mais pouvant prendre en charge le jeu d’instructions 32 bits du 80386); le Motorola 68000 avait une unité ALU 16 bits avec des registres et des adresses 32 bits; il y avait des ordinateurs centraux IBM avec des adresses 15 bits, 24 bits ou 31 bits. Vous voyez également toujours différentes tailles d'ALU et de bus d'adresses dans les systèmes intégrés.
Chaque fois que int
est inférieur à size_t
, et vous essayez de stocker la taille ou le décalage d’un très gros fichier ou objet dans un unsigned int
, il est possible qu’il déborde et cause un bogue. Avec int
, il est également possible d’obtenir un nombre négatif. Si un int
ou unsigned int
est plus large, le programme fonctionnera correctement mais vous perdez de la mémoire.
Vous devez généralement utiliser le type correct à cette fin si vous souhaitez une portabilité. Beaucoup de gens vous recommanderont d’utiliser des mathématiques signées au lieu de non signées (pour éviter les bogues vicieux et subtils comme 1U < -3
). Pour cela, la bibliothèque standard définit ptrdiff_t
dans <stddef.h>
comme type signé du résultat de la soustraction d’un pointeur à un autre.
Cela dit, une solution de contournement pourrait être de bounds-check toutes les adresses et tous les décalages par rapport à INT_MAX
et soit 0
ou INT_MIN
_ selon le cas, et activez les avertissements du compilateur concernant la comparaison des quantités signées et non signées au cas où vous en manqueriez une. De toute façon, vous devriez toujours, toujours, toujours vérifier vos accès à la matrice pour les débordements en C.
La définition de SIZE_T
se trouve à: https://msdn.Microsoft.com/en-us/library/cc441980.aspx et https://msdn.Microsoft.com/en-us /library/cc230394.aspx
Collez ici les informations requises:
SIZE_T
est un ULONG_PTR
représentant le nombre maximal d'octets vers lesquels un pointeur peut pointer.
Ce type est déclaré comme suit:
typedef ULONG_PTR SIZE_T;
UNE ULONG_PTR
est un type long non signé utilisé pour la précision du pointeur. Il est utilisé lors du transtypage d'un pointeur sur un type long pour effectuer une arithmétique de pointeur.
Ce type est déclaré comme suit:
typedef unsigned __int3264 ULONG_PTR;