45 votes

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

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

J'ai aussi lu que sizeof(int) est de 4 octets lorsqu'il est compilé avec à la fois 32 et 64 bits compilateur .

Supposons que mon processeur puisse exécuter des applications 32 bits et 64 bits, qui jouera le rôle principal dans le choix de la taille des données ? le site le compilateur ou le processeur ?

47 votes

Le processeur exécute le code machine, il ne décide rien.

0 votes

Je me suis dit qu'un @StoryTeller s'intéresserait à l'épistémologie :-)

3 votes

"Supposons que mon processeur puisse exécuter des applications 32 bits et 64 bits, qui jouera le rôle principal dans la décision de la taille des données, le compilateur ou le processeur ?" Le nombre de bits que votre CPU supporte ou non n'a aucune importance. Une fois que l'application est compilée, la taille est "intégrée dans les fichiers binaires de l'application". pour ainsi dire . Si votre processeur ne peut pas traiter le binaire, l'application ne peut pas fonctionner.

44voto

Prof. Falken Points 10242

C'est finalement le compilateur. L'implémentateur du compilateur peut décider d'émuler n'importe quelle taille d'entier qu'il juge appropriée, indépendamment de ce que le CPU gère le plus efficacement. Cela dit, la norme C (et C++) est écrite de telle sorte que le compilateur est libre de choisir la méthode la plus rapide et la plus efficace. Pour de nombreux compilateurs, les responsables de l'implémentation ont choisi de conserver int en tant que 32 bits, bien que le CPU gère nativement les ints 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 à ce qu'un int soit 32 bits et pas plus. (Cela pourrait aussi être, comme l'utilisateur L'utilisateur3386109 souligne que les données 32 bits étaient préférées parce qu'elles prennent moins de place et peuvent donc être accédées plus rapidement).

Donc si vous voulez être sûr d'obtenir des ints 64 bits, vous utilisez int64_t au lieu de int pour déclarer votre variable. Si vous savez que votre valeur tiendra dans 32 bits ou que 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 <code>struct</code> ils sont composés à partir de types de base tels que <code>int</code> .

0 votes

Oui, mais le compilateur définit également la taille en fonction du processeur cible. C'est donc le compilateur qui utilise les informations sur le processeur.

2 votes

@Justin, abordé dans la partie sur la façon dont le compilateur a beaucoup de marge de manœuvre pour choisir les tailles qui donnent les résultats les plus rapides ou les plus efficaces.

3 votes

Ou bien les 32 bits sont utilisés pour économiser de la mémoire et améliorer les performances du cache. Il ne faut pas beaucoup d'ints 64 bits pour remplir une ligne de cache.

26voto

Art Points 6040

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

Le compilateur ne peut pas inventer n'importe quoi. Il doit adhérer à la bonne ABI[1] que le système d'exploitation fournit. Si les structures et les appels système fournis par le système d'exploitation ont des types ayant certaines tailles et exigences d'alignement, le compilateur n'est pas vraiment libre d'inventer sa propre réalité, à moins que les développeurs du compilateur ne veuillent réimplémenter des fonctions enveloppes 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 inventée, elle doit faire ce qui peut être raisonnablement fait sur le CPU. Et très souvent, l'ABI d'un système d'exploitation sera très similaire à d'autres ABI d'autres systèmes d'exploitation sur la même unité centrale, car il est plus facile de réutiliser le travail effectué (sur les compilateurs, entre autres).

Dans le cas des ordinateurs qui supportent à la fois le code 32 bits et le code 64 bits, le système d'exploitation doit encore travailler pour supporter l'exécution des programmes dans les deux modes (parce que le système doit fournir deux ABI différentes). Certains systèmes d'exploitation ne le font pas et sur ceux-là, vous n'avez pas le choix.

[1] ABI signifie Application Binary Interface. Il s'agit d'un ensemble de règles sur la façon dont un programme interagit avec le système d'exploitation. Elle définit la manière dont un programme est stocké sur le disque pour être exécutable par le système d'exploitation, la manière de faire des appels système, la manière de se lier à des bibliothèques, etc. Mais pour pouvoir se lier à des bibliothèques par exemple, votre programme et la bibliothèque doivent se mettre d'accord sur la façon de faire des appels de fonction entre votre programme et la bibliothèque (et vice versa) et pour pouvoir faire des appels de fonction, le programme et la bibliothèque doivent avoir la même idée de la disposition de la pile, 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, ce qui inclut les tailles, l'alignement et la signature des types.

1 votes

L'ABI contient également des conventions d'appel, c'est-à-dire un ensemble de règles sur la façon dont le programme appelle les fonctions. Elle contient également des contraintes imposées par le processeur (par exemple, des contraintes d'alignement pour divers types de données primitives).

4 votes

Il n'est pas nécessaire qu'un compilateur prenne en charge un moyen quelconque permettant à un programme d'interagir avec quoi que ce soit dans le monde extérieur sans passer par les fonctions de la bibliothèque qui sont fournies avec le compilateur. Rien n'interdit à une implémentation ciblant x64 d'utiliser un type d'entier 36 bits à complément à un (en effectuant toutes les opérations de décalage et de masquage nécessaires pour émuler cela). Une telle implémentation pourrait être réellement utile si quelqu'un avait du code Univac à exécuter mais qu'il ne disposait pas d'un système 36 bits fonctionnel.

1 votes

@supercat Je n'ai jamais dit qu'il y avait des exigences de ce genre. J'ai juste décrit la réalité telle qu'elle est.

8voto

user3344003 Points 3070

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 fonctionne sur votre Mac. Le Mac et l'iPhone/iPac utilisent des processeurs différents. Rien dans votre Mac ne dit au compilateur quelle taille doit être utilisée pour l'int sur l'iPad.

1 votes

Si vous voulez vous opposer La réponse de Art alors tu en fais trop. Je suppose que sa réponse faisait référence au système cible, et non à l'hôte sur lequel le compilateur croisé s'exécute, alors que vous parlez du système hôte, qui, bien sûr, n'a rien à voir avec les tailles des types de données sur la cible.

2 votes

Ce n'est tout simplement pas vrai. Au moins, vous admettez les "spécifications du langage", mais chaque système a une norme (ABI) pour la taille du "int" par défaut, comment les paramètres sont passés aux fonctions, etc... par exemple pour les applications iOS, ce guide du développeur Apple l'explique clairement :

0 votes

(citation) Lorsque différents morceaux de code doivent fonctionner ensemble, ils doivent respecter des conventions standard convenues sur la façon dont le code doit agir. Ces conventions portent notamment sur la taille et le format des types de données courants, ainsi que sur les instructions utilisées lorsqu'un morceau de code en appelle un autre. Les compilateurs sont mis en œuvre sur la base des conventions suivantes afin qu'ils puissent émettre un code binaire qui fonctionne ensemble. Collectivement, ces conventions sont désignées sous le nom d'interface binaire d'application (ABI).

5voto

plugwash Points 795

Le concepteur du processeur détermine quels registres et instructions sont disponibles, quelles sont les règles d'alignement pour un accès efficace, quelle est la taille des adresses mémoire, etc.

La norme C fixe des exigences minimales pour les types intégrés. "char" doit être d'au moins 8 bits, "short" et "int" d'au moins 16 bits, "long" d'au moins 32 bits et "long long" d'au moins 64 bits. Il est également précisé que "char" doit être équivalent à la plus petite unité de mémoire que le programme peut adresser et que l'ordre de taille des types standard doit être maintenu.

D'autres normes peuvent également avoir un impact. Par exemple, la version 2 de la "spécification Unix unique" stipule que int doit être au moins de 32 bits.

Enfin, le code existant a un impact. Le portage est déjà assez difficile, personne ne veut le rendre plus difficile que nécessaire.


Lors du portage d'un système d'exploitation et d'un compilateur sur un nouveau processeur, il faut définir ce que l'on appelle un "ABI C". Cela définit la façon dont les codes binaires communiquent entre eux.

  • Les exigences de taille et d'alignement des types intégrés.
  • Les règles d'emballage des structures (et donc leur taille).
  • Comment les paramètres sont passés et retournés
  • Comment la pile est gérée

En général, une fois qu'une ABI est définie pour une combinaison de famille de CPU et d'OS, elle ne change pas beaucoup (parfois la taille de types plus obscurs comme "long double" change). La modifier entraîne un grand nombre de ruptures pour un gain relativement faible.

De même, ceux qui portent un système d'exploitation sur une plate-forme présentant des caractéristiques similaires à une plate-forme existante choisiront généralement les mêmes tailles que sur les plates-formes précédentes sur lesquelles le système d'exploitation a été porté.


Dans la pratique, les fournisseurs de systèmes d'exploitation et de compilateurs choisissent généralement l'une des quelques combinaisons de tailles pour les types d'entiers de base.

  • "LP32" : char est 8 bits. short et int sont 16 bits, long et pointeur sont 32 bits. Couramment utilisé sur les plateformes 8 bits et 16 bits.
  • "ILP32" : char est 8 bits, short est 16 bits. int, long et pointeur sont tous 32 bits. Si un long existe, il est de 64 bits. Couramment utilisé sur les plateformes 32 bits.
  • "LLP64" : char est 8 bits. short est 16 bits. int et long sont 32 bits. long long et pointeur sont 64 bits. Utilisé sous Windows 64 bits.
  • "LP64" : char est 8 bits. short est 16 bits. int est 32 bits. long, long long et pointeur sont 64 bits. Utilisé sur la plupart des systèmes 64 bits de type Unix.
  • "ILP64" : char est 8 bits, short est 16 bits, int, long et pointeur et long long sont tous 64 bits. Apparemment utilisé sur certains des premiers systèmes d'exploitation 64 bits, mais rarement vu de nos jours.

Les processeurs 64 bits peuvent généralement exécuter des binaires 32 bits et 64 bits. En général, cela est géré par une couche de compatibilité dans votre système d'exploitation. Ainsi, votre binaire 32 bits utilise les mêmes types de données qu'il utiliserait sur un système 32 bits, puis la couche de compatibilité traduit les appels système afin que le système d'exploitation 64 bits puisse les gérer.

3voto

Lorehead Points 953

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 arrive souvent que la compatibilité avec une norme existante 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 stipule qu'un wchar_t doit être plus large que 16 bits, et sur Linux, il est de 32 bits, mais il a toujours été de 16 bits sur Windows, de sorte que les compilateurs pour Windows choisissent tous d'être compatibles avec l'API Windows au lieu de la norme du langage. Une grande partie du code hérité, tant pour Linux que pour Windows, suppose qu'un fichier de type long est exactement de 32 bits de large, tandis que d'autres codes supposaient qu'il était assez large pour contenir un horodatage en secondes ou une adresse IPv4 ou un offset de fichier ou les bits d'un pointeur, et (après qu'un compilateur ait défini int comme une largeur de 64 bits et long comme une largeur de 32 bits), la norme linguistique a établi une nouvelle règle selon laquelle int ne peut être plus large que long .

En conséquence, les compilateurs courants de ce siècle choisissent de définir int comme une largeur de 32 bits, mais historiquement, certains l'ont définie comme une largeur de 16 bits, 18 bits, 32 bits, 64 bits et d'autres tailles. Certains compilateurs vous laissent choisir si long sera d'une largeur de 32 bits exactement, comme le suppose certains codes hérités, ou aussi large qu'un pointeur, comme le suppose d'autres codes hérités.

Cela montre comment les hypothèses que vous faites aujourd'hui, comme le fait qu'un type soit toujours de 32 bits de large, peuvent se retourner contre vous à l'avenir. Cela est déjà arrivé deux fois aux bases de code C, lors des transitions vers le code 32 bits et 64 bits.

Mais qu'est-ce que vous devriez vraiment utiliser ?

El int est rarement utile de nos jours. Il existe généralement un autre type que vous pouvez utiliser et qui garantit davantage ce que vous obtiendrez. (Il y a un avantage : les types qui ne sont pas aussi larges qu'une variable de type int pourrait être automatiquement élargi à int ce qui pourrait provoquer quelques bogues vraiment bizarres lorsque vous mélangez des types signés et non signés et int est le plus petit type dont on garantit qu'il ne sera pas plus court que int .)

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

Si vous voulez le type le plus rapide qui a 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 le document <stdint.h> .) Si vous voulez le plus petit type qui a au moins 32 bits de large, pour mettre le plus de données 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 votre compilateur a un type comme ça c'est int32_t Si vous voulez quelque chose qui a une largeur de 32 bits sur une machine 32 bits et de 64 bits 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 faire de l'indexation de tableau et des calculs de pointeurs, c'est ptrdiff_t 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 !

0 votes

"la norme linguistique dit qu'une wchar_t doit être plus large que 16 bits" -- chapitre et verset ? Je suis presque sûr que ça ne dit pas ça, dans aucune version, en tout cas pas explicitement . L'ambiguïté de la norme quant à la largeur de l'ouvrage. vraiment supposé être est pourquoi char16_t y char32_t ont été introduits.

0 votes

La norme ne dit pas que wchar_t doit être plus large que 8 bits, et ne spécifie pas non plus quel jeu de caractères est utilisé (un système pourrait en principe utiliser wchar 16 bits pour un codepage local spécifique à l'Asie de l'Est, par exemple, ou bien wchar_t pour un jeu de caractères spécifique à l'Asie de l'Est). seulement supportent le BMP), mais il est assez clair que l'utilisation de codages à longueur variable ou à état n'est pas acceptable.

0 votes

@Random832 La norme dit que wchar_t est "un type entier dont la plage de valeurs peut représenter des codes distincts pour tous les membres du plus grand jeu de caractères étendu spécifié parmi les locales prises en charge". Vous avez raison dans le sens où une implémentation donnée n'est pas obligée de fournir une locale qui supporte Unicode - ou même ASCII. Cependant, la norme fait nécessitent la prise en charge des chaînes de caractères UTF-8, UTF-16 et UCS-32 et d'une char32_t type. Si vous voulez être compatible avec les locales de Microsoft : setlocale(".1200"); nécessite à elle seule la prise en charge de l'ensemble de l'Unicode. Et l'API Windows exige UTF-16.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X