c++ - supprimer - tag&rename 3.9 14




Qui décide de la taille de tout type de données ou structure(en fonction de 32 bits ou 64 bits)? (5)

Qui décide de la taille de tout type de données ou structure (en fonction de 32 bits ou 64 bits)? Le compilateur ou le processeur? Par exemple, sizeof(int) est de 4 octets pour un système 32 bits alors que c'est 8 octets pour un système 64 bits.

J'ai également lu que sizeof(int) est de 4 octets lorsqu'il est compilé à l'aide d'un compilateur 32 bits et 64 bits .

Supposons que mon processeur puisse exécuter à la fois des applications 32 bits et 64 bits. Qui jouera le rôle principal dans la détermination de la taille des données du compilateur ou du processeur ?


C’est strictement, à 100%, entièrement le compilateur qui décide de la valeur de sizeof (int). Ce n'est pas une combinaison du système et du compilateur. C'est juste le compilateur (et les spécifications du langage C / C ++).

Si vous développez des applications pour iPad ou iPhone, le compilateur est exécuté sur votre Mac. Le Mac et l'iPhone / iPac utilisent des processeurs différents. Rien sur votre Mac ne dit au compilateur quelle taille utiliser pour un int sur iPad.


C'est finalement le compilateur. Les développeurs du compilateur peuvent décider d’émuler la taille d’entier qu’ils jugent appropriée, indépendamment de ce que le CPU gère le plus efficacement possible. Cela dit, le standard C (et C ++) est écrit de telle sorte que l’implémenteur du compilateur est libre de choisir le moyen le plus rapide et le plus efficace. Pour de nombreux compilateurs, les développeurs ont choisi de conserver int en 32 bits, bien que le processeur gère nativement les entrées 64 bits de manière très efficace.

Je pense que cela a été fait en partie pour augmenter la portabilité vers les programmes écrits lorsque les machines 32 bits étaient les plus courantes et qui s'attendaient à un int de 32 bits et non plus. (Il se pourrait également, comme l’utilisateur user3386109 l’a souligné , que les données 32 bits soient préférées car elles prennent moins de place et peuvent donc être consultées plus rapidement.)

Donc, si vous voulez vous assurer que vous obtenez un ints de 64 bits, utilisez int64_t au lieu de int pour déclarer votre variable. Si vous savez que votre valeur tiendra dans 32 bits ou si vous ne vous souciez pas de la taille, vous utilisez int pour laisser le compilateur choisir la représentation la plus efficace.

Quant aux autres types de données tels que struct , ils sont composés des types de base tels que int .


Ce n'est pas le processeur, ni le compilateur, ni le système d'exploitation. C'est tous les trois en même temps.

Le compilateur ne peut pas inventer des choses. Il doit adhérer à la bonne ABI [1] fournie par le système d'exploitation. Si les structures et les appels système fournis par le système d'exploitation ont des types avec certaines tailles et exigences d'alignement, le compilateur n'est pas vraiment libre de créer sa propre réalité à moins que les développeurs du compilateur ne veuillent réimplémenter des fonctions d'encapsulation pour tout ce que le système d'exploitation fournit. Dans ce cas, l’ABI du système d’exploitation ne peut pas être complètement constituée, elle doit faire ce qui peut être raisonnablement fait sur le processeur. Et très souvent, les ABI d’un système d’exploitation ressemblent beaucoup aux autres ABI d’autres systèmes d’exploitation sur le même processeur, car il est plus facile de simplement réutiliser leur travail (sur des compilateurs, entre autres).

Dans le cas d'ordinateurs prenant en charge les codes 32 bits et 64 bits, le système d'exploitation doit encore effectuer des tâches pour prendre en charge les programmes en cours d'exécution dans les deux modes (car le système doit fournir deux ABI différentes). Certains systèmes d'exploitation ne le font pas et sur ceux qui n'ont pas le choix.

[1] ABI signifie Application Binary Interface (interface binaire d'application). C'est un ensemble de règles pour la manière dont un programme interagit avec le système d'exploitation. Il définit comment un programme stocké sur disque doit être exécuté par le système d'exploitation, comment faire des appels système, comment se connecter à des bibliothèques, etc. Mais pour pouvoir se connecter à des bibliothèques par exemple, votre programme et la bibliothèque doivent être d'accord. pour effectuer des appels de fonction entre votre programme et la bibliothèque (et inversement) et pour pouvoir effectuer des appels de fonction, le programme et la bibliothèque doivent avoir la même idée de la disposition des piles, de l’utilisation des registres, des conventions d’appel de fonction, etc. Et pour les appels de fonction, vous devez vous mettre d’accord sur la signification des paramètres, notamment la taille, l’alignement et la signature des types.


Le compilateur décide de la taille des types de base et de la disposition des structures. Si une bibliothèque déclare des types, elle décidera de la manière dont ceux-ci sont définis et donc de leur taille.

Cependant, il est fréquent que la compatibilité avec un standard existant et la nécessité de se lier à des bibliothèques existantes produites par d'autres compilateurs obligent une implémentation donnée à faire certains choix. Par exemple, la norme de langage indique qu'un wchar_t doit avoir une largeur supérieure à 16 bits. Sous Linux, il a une largeur de 32 bits. Toutefois, Windows a toujours été au format 16 bits. Les compilateurs pour Windows ont donc tous choisi d'être compatibles avec l'API Windows. au lieu de la norme de langue. Un grand nombre de codes hérités pour Linux et Windows supposent qu'une long exactement 32 bits, tandis que d'autres supposent une largeur suffisante pour contenir un horodatage en secondes, une adresse IPv4 ou un décalage de fichier ou les bits d'un pointeur. (après un compilateur défini par int comme largeur de 64 bits et long de 32 bits), le standard de langage a créé une nouvelle règle qui ne peut pas être plus large que long .

En conséquence, les compilateurs traditionnels de ce siècle ont choisi de définir int comme ayant une largeur de 32 bits, mais historiquement, certains l'ont défini comme étant de 16 bits, 18 bits, 32 bits, 64 bits et autres tailles. Certains compilateurs vous permettent de choisir si la long doit avoir exactement 32 bits de large, comme le suppose certains codes hérités, ou aussi large qu'un pointeur, comme le suppose les autres codes hérités.

Cela montre que les hypothèses que vous faites aujourd'hui, comme si certains types avaient toujours une largeur de 32 bits, pourraient revenir vous mordre à l'avenir. Cela s'est déjà produit deux fois pour les bases de code C, lors des transitions vers le code 32 bits et le code 64 bits.

Mais que devriez-vous réellement utiliser ?

Le type int est rarement utile de nos jours. Il existe généralement un autre type d’utilisation que vous pouvez utiliser qui garantit davantage ce que vous obtiendrez. (Il y a un avantage: les types qui ne sont pas aussi larges qu'un int peuvent être automatiquement élargis à int , ce qui peut causer quelques bogues vraiment bizarres lorsque vous mélangez des types signés et non signés, et int est le plus petit type garanti ne pas être plus court que int .)

Si vous utilisez une API particulière, vous souhaiterez généralement utiliser le même type. Il existe de nombreux types dans la bibliothèque standard à des fins spécifiques, tels que clock_t pour les ticks d'horloge et time_t pour le temps en secondes.

Si vous voulez le type le plus rapide ayant une largeur d'au moins 16 bits, c'est int_fast16_t et il existe d'autres types similaires. (Sauf indication contraire, tous ces types sont définis dans <stdint.h> .) Si vous voulez le type le plus petit ayant une largeur d'au moins 32 bits, vous devez intégrer le plus de données possible dans vos tableaux, c'est int_least32_t . Si vous voulez le type le plus large possible, c'est intmax_t . Si vous savez que vous voulez exactement 32 bits et que votre compilateur a un type comme ça , c'est int32_t Si vous voulez quelque chose de 32 bits de large sur une machine 32 bits et de 64 bits de large sur une machine 64 bits, et toujours à la bonne taille pour stocker un pointeur, c'est intptr_t . Si vous voulez un bon type pour l'indexation sur les tableaux et les maths de pointeur, c'est ptrdiff_t partir de <stddef.h> . (Celui-ci est dans un en-tête différent car il provient de C89 et non de C99.)

Utilisez le type que vous voulez vraiment dire!


Lorsque vous parlez de compilateur, vous devez avoir une image claire de build|host|target , c’est-à-dire de la machine sur laquelle vous construisez (build), de la machine pour laquelle vous construisez (hôte) et de la machine produite par GCC. code pour (cible), car pour "compilation croisée" est très différent de "compilation native".

Pour ce qui est de la question "qui décide du type de données et de la structure sizeof", cela dépend du système cible pour lequel vous avez demandé au compilateur de générer des binaires. Si la cible est 64 bits, le compilateur traduira sizeof (long) en 8, et si la cible est un ordinateur 32 bits, il compilera sizeof (long) en 4. Tous ces éléments ont été prédéfinis par le fichier d'en-tête que vous avez utilisé pour la construction. votre programme. Si vous lisez votre $ MAKETOP / usr / include / stdint.h, il y a des typedefs pour définir la taille de votre type de données.

Pour éviter l'erreur créée par la différence de taille, Google-style style-Integer_Types recommande d'utiliser des types tels que int16_t, uint32_t, int64_t, etc. Ceux-ci ont été définis dans <stdint.h> .

Ci-dessus se trouvent uniquement les `Plain Old Data ', telles que int. Si vous parlez d'une structure, il existe une autre histoire, car la taille d'une structure dépend de l' alignement du tassement , de l'alignement des limites de chaque champ de la structure, ce qui aura un impact sur la taille de la structure.





operating-system