Comment un ordinateur détermine-t-il le type de données d'un octet?

31

Par exemple, si l'ordinateur a 10111100stocké sur un octet particulier de RAM, comment l'ordinateur sait-il interpréter cet octet comme un entier, un caractère ASCII ou autre chose? Les données de type sont-elles stockées dans un octet adjacent? (Je ne pense pas que ce serait le cas car cela entraînerait l'utilisation de deux fois la quantité d'espace pour un octet.)

Je soupçonne qu'un ordinateur ne connaît peut-être même pas le type de données, que seul le programme l'utilisant sait. Ma conjecture est que parce que la RAM est R AM et donc pas lue séquentiellement, un programme particulier dit simplement au CPU de récupérer les informations à partir d'une adresse spécifique et le programme définit comment les traiter. Cela semblerait correspondre à des choses de programmation telles que la nécessité de transtypage.

Suis-je sur la bonne voie?

Bassinateur
la source
4
Remarque: si vous parlez de types, vous devez le faire dans un contexte linguistique. C'est au compilateur de gérer ce genre de choses (symboles, types de vérification, opérations, transtypage, ram d'adresse, etc.). Le CPU et la RAM ne connaissent que les octets
jean
4
Le type de données d'un octet est un octet. Au-delà, l'ordinateur ne sait rien. Un programme peut interpréter un octet ou un groupe d'octets comme un type de données particulier et tenter d'effectuer des opérations sur ceux-ci, mais il n'y a aucune restriction. Le même groupe d'octets peut être interprété comme plus d'un type de données (c'est-à-dire que les pointeurs sont convertis en types de valeur, unions de type C, etc.). Le fait que la RAM ne soit pas lue séquentiellement n'est pas vraiment pertinent. - C'est plus parce que la RAM est à usage général. - Les registres par exemple ne sont pas non plus lus séquentiellement, mais ils sont dactylographiés.
BrainSlugs83
5
Plug sans vergogne pour moi, mais cette question a été essentiellement posée sur les programmeurs SE il y a environ un mois. Voici ma réponse . Il est un peu long à ce stade, mais l'attaque sous plusieurs angles différents.
Shaz
2
Une conséquence utile du fait que le matériel est indépendant du type de données est qu'un seul octet (ou mot, etc.) peut être interprété de plusieurs manières par un programme. Notamment, l'interprétation temporaire d'un nombre à virgule flottante comme un entier est utilisée pour calculer la racine carrée inverse rapide .
Aoeuid
@ BrainSlugs83, pourriez-vous envisager de convertir cela en réponse?
DW

Réponses:

38

Votre suspicion est correcte. Le CPU ne se soucie pas de la sémantique de vos données. Parfois, cependant, cela fait une différence. Par exemple, certaines opérations arithmétiques produisent des résultats différents lorsque les arguments sont sémantiquement signés ou non signés. Dans ce cas, vous devez indiquer au processeur quelle interprétation vous souhaitez.

C'est au programmeur de donner un sens à ses données. Le CPU n'obéit qu'aux ordres, ignorant béatement leur signification ou leurs objectifs.

Yuval Filmus
la source
1
Concernant "quand les arguments sont sémantiquement signés ou non signés", comment le CPU le saurait-il? Les opérations du processeur ne voient que les octets de paramètres et manquent de ce type de connaissance du contexte du type de données. Vous impliquez le type de données en choisissant l'opération CPU appropriée (ou votre compilateur le fait).
Shiv
4
@Shiv Dans de tels cas, le processeur reçoit en fait une instruction différente pour traiter les numéros signés par rapport aux numéros non signés. Comme dans les soupçons de l'OP, le programme est obligé de fournir ces détails, car le CPU n'est pas au courant.
Cort Ammon - Reinstate Monica
2
Je travaille avec des ordinateurs depuis aussi longtemps que je me souvienne de moi, et même si je sais que le CPU ne se soucie pas des constructions de haut niveau que nous utilisons sur la programmation de haut niveau, mais cette séparation des concepts me fait encore peur de temps en temps
Loupax du
1
@Loupax Eh bien, travailler avec un assemblage de très bas niveau aide pas mal - c'est même un peu mov al, 42de haut niveau - il est évident qu'il n'y a qu'une seule instruction possible que cela pourrait appeler, mais elle est encore quelque peu abstraite. Cependant, l'utilisation mov.8 al, 42explicite rend cela douloureusement évident :)
Luaan
1
@Shiv: Je voudrais noter qu'il existe des machines où les données en mémoire sont tapées. Celles-ci sont appelées architectures de mémoire étiquetées (ou simplement architectures étiquetées), mais elles n'ont pas eu autant de succès commercial que les architectures normales, en partie parce que nous programmons maintenant principalement dans des langages compilés au lieu de l'assemblage et le compilateur se charge de taper. Voir: en.wikipedia.org/wiki/Tagged_architecture
slebetman
14

Comme d'autres l'ont déjà répondu, les CPU courants d'aujourd'hui ne savent pas ce que contient une position de mémoire donnée; le logiciel décide.

Cependant, il existe d'autres possibilités. Lisp Machines a par exemple utilisé une architecture balisée qui stockait le type de chaque position mémoire; de cette façon, le matériel lui-même pourrait faire une partie du travail des langages de haut niveau.

Et même maintenant, je suppose que vous pouvez considérer que le bit NX dans Intel, AMD, ARM et d'autres architectures suit le même principe: distinguer au niveau matériel si une zone mémoire donnée contient des données ou des instructions.

De plus, juste pour être complet, dans les architectures Harvard (comme certains microcontrôleurs), les données et les instructions sont physiquement séparées, de sorte que le CPU a une certaine idée de ce qu'il lit.

Dans cette question Quora, il y a des commentaires sur le fonctionnement de la mémoire balisée, ses implications et sa disparition en termes de performances, etc.

hmijail
la source
L'architecture balisée est une note intéressante. Serait-ce beaucoup plus rapide?
Bassinator
4

Oui. Le programme obtient juste un octet de la mémoire et il peut l'interpréter comme il le souhaite.

David Richerby
la source
3

Il n'y a pas d'annotations de type.
La RAM stocke des données pures, puis le programme définit ce qu'il faut faire.

Avec les registres CPU, c'est un peu plus difficile, si vous avez des registres de type donné (comme FPU), vous dites ce qu'il y a à l'intérieur.
Les opérations sur les registres à virgule flottante utilisent explicitement des données typées. Vous ou votre compilateur dites quoi et quand y mettre, donc vous n'avez pas une telle liberté.
L'ordinateur ne fait aucune hypothèse sur les données sous-jacentes dans la RAM, et dans les registres à une exception près - les registres typés dans le CPU sont de type connu, optimisés pour les traiter. C'est seulement pour montrer qu'il y a des endroits où les données doivent être du type attendu, mais rien ne vous empêche de convertir des chaînes en flottants et de les multiplier.

Dans les langages de programmation, vous spécifiez le type, ou dans les langages de niveau supérieur, les données sont générales et le compilateur / interprète / VM code ce qui se trouve à l'intérieur avec une surcharge.
Par exemple, en C, votre type de pointeur indique quoi faire avec les données, comment y accéder.

Bien sûr, vous pouvez lire des chaînes (caractères) et les traiter comme des valeurs à virgule flottante, des entiers et les mélanger.

Mal
la source
Même les bits d'un registre FPU ne représentent pas toujours des valeurs à virgule flottante. Autrefois (peut-être moins maintenant?), Une optimisation courante consistait à utiliser des registres à virgule flottante (64 bits ou plus) pour copier les données plus rapidement que les registres à usage général / entier (32 bits), étant deux fois plus gros, ils étaient généralement capables de copier des données deux fois plus rapidement.
Seth
1
Je suis totalement d'accord avec vous, c'est pourquoi j'ai écrit que quelqu'un pourrait y pousser des chaînes. Et en même temps, les gens faisaient des opérations en virgule flottante sur des entiers, car c'était plus rapide. C'est le but!
Evil
@HCBPshenanigans, il existe des instructions qui manipulent les valeurs à virgule flottante. Si FADD est utilisé, il est logique que les groupes de mémoire (4,8 ou 10) octets contiennent des nombres à virgule flottante. C'est vrai pour plusieurs types d'instructions: multiplier deux entiers n'a de sens que s'ils sont des entiers, sauter n'a de sens que s'il s'agit d'une adresse.
JDługosz
@seth et evilJS qui ne sont pas supposés être le cas pour les instructions 8087 empilées en virgule flottante héritées, mais c'est le cas pour les nouveaux registres CIMD qui peuvent être utilisés uniquement pour le chargement / enregistrement sans interprétation (bien qu'ils doivent être alignés), et une mise en garde que si les registres CIMD n'ont jamais été utilisés, ils n'ont pas besoin d'être enregistrés dans un changement de contexte. Si vous (seulement) déplacez 8 octets via le registre XMM, c'est une perte nette car l'ensemble doit être sauvegardé.
JDługosz
3

Le CPU s'en fiche, il exécute le code assembleur, qui déplace simplement les données, les décale, les ajoute ou les multiplie ...

Les types de données sont un concept de langage de niveau supérieur: en C ou C ++, vous devez spécifier des types pour chaque élément de données que vous manipulez; le compilateur C / C ++ se charge de transformer ces éléments de données en commandes appropriées à traiter par le processeur (les compilateurs écrivent le code assembleur)

Dans certains langages de niveau encore plus élevé, les types peuvent être déduits: en Python ou Javascript, par exemple, il n'est pas nécessaire de spécifier les types de données, mais les données ont un type et vous ne pouvez pas ajouter une chaîne avec un entier, mais vous pouvez ajouter un flottant avec un entier: le 'compilateur' (qui dans le cas de Javascript est un compilateur JIT (Just in Time). Javascript est souvent appelé un langage 'interprété' parce que les navigateurs interprétaient historiquement le code Javascript, mais de nos jours les moteurs Javascript sont des compilateurs.

Le code finit toujours par être compilé en code machine, mais le format du code machine dépend évidemment de la machine que vous ciblez (le code x86 64 bits ne fonctionnera pas sur une machine x86 32 bits ou un processeur ARM par exemple)

Il y a donc en fait beaucoup de couches impliquées dans l'exécution de code interprété.

Java et C # sont d'autres intéressants, car le code Java ou C # est techniquement `` compilé '' en un binaire Java (bytecode), mais ce code lui-même est ensuite interprété par Java Runtime, qui est spécifique au matériel sous-jacent (il faut installer le JRE ciblant la bonne machine pour exécuter les binaires Java (Jars))

MrE
la source
Un compilateur compile, que ce soit en JIT ou non; et un interprète interprète sans compiler (car sinon ce serait un compilateur!). Ce sont des choses très différentes. Et en ce qui concerne "Java étant drôle" en raison de l'interprétation du bytecode, considérez que même le code machine x86 sera réellement interprété (ou même compilé?) Par le microprocesseur même en microcode .
hmijail
Merci pour la clarification ... D'accord: un compilateur compile et un interprète interprète. Dans le cas de Javascript, l'histoire est un peu compliquée, car certains navigateurs plus anciens interprètent le code, tandis que les navigateurs plus modernes compilent en fait juste à temps, ce qui explique probablement pourquoi il est toujours appelé langage «interprété» même s'il n'est techniquement plus.
MrE
Mais AFAIK, JS commence à être interprété, puis peut être compilé au besoin. Et les JIT peuvent passer d'interprété à compilé en interprété à nouveau, en fonction de beaucoup de choses. Par exemple, un morceau de code peut être compilé pour une variable ayant un type donné; mais ensuite le code est exécuté à nouveau avec cette variable ayant un type différent, de sorte que le code compilé existant ne peut pas être utilisé de sorte que l'interprète intervient - jusqu'à ce que le code soit à nouveau compilé pour le nouveau type ...
hmijail
Vous me citez sur quelque chose que je n'ai pas dit, veuillez le retirer car c'est totalement faux. Le microcode n'a RIEN à voir avec l'OS; c'est quelque chose interne au microprocesseur. 32 bits ou 64 bits n'a rien à voir avec cela.
hmijail
3

Les types de données ne sont pas une fonctionnalité matérielle. Le CPU connaît un couple (enfin, beaucoup) de commandes différentes. Ceux-ci sont appelés le jeu d'instructions d'un CPU.

L'un des plus connus est le jeu d'instructions x86 . Si vous recherchez "multiplier" sur cette page, vous obtenez 50 résultats. MULPDet MULSDpour la multiplication des doubles, FIMULpour la multiplication entière, ...

Ces commandes fonctionnent sur les registres. Les registres sont des emplacements de mémoire qui peuvent contenir un nombre fixe de bits (souvent 32 ou 64, selon l'architecture que votre CPU utilise), peu importe ce que ces bits représentent. Par conséquent, l'instruction CPU interprète les valeurs des registres d'une manière différente, mais les valeurs elles-mêmes n'ont pas de types.

Un exemple a été donné à PyCon 2017 par Stuart Williams :

entrez la description de l'image ici

Martin Thoma
la source
1
Notez que ce n'est pas strictement vrai: il existe des registres à usage spécial qui ne peuvent pas contenir de valeurs arbitraires (par exemple, des registres de pointeurs qui ne sont pas n'importe quelle adresse et n'autorisent pas les ajouts arbitraires, ou des registres à virgule flottante où vous pouvez 'ne stocke pas les valeurs non normalisées). Mais votre réponse est correcte pour les registres à usage général sur la plupart des architectures.
Gilles 'SO- arrête d'être méchant'
2

... qu'un programme particulier indique simplement au CPU de récupérer les informations à partir d'une adresse spécifique et le programme définit comment les traiter.

Exactement. Mais la RAM n'est pas lue "séquentiellement", et cela signifie Random Access Memory qui est exactement le contraire.

En plus de savoir ce qu'est un octet est , vous ne savez même pas si c'est un octet , ou un fragment d'un élément comme un plus grand nombre à virgule flottante.

Je voudrais ajouter à d'autres réponses en donnant quelques exemples spécifiques.

Considérez 01000001. Le programme peut le copier d'un endroit à un autre dans le cadre d'un grand volume de données sans aucun égard à sa signification. Mais en copiant cela à l'adresse utilisée par le tampon vidéo en mode texte, la lettre As'affichera à un certain endroit sur l'écran. La même action exacte lorsque la carte est en mode graphique CGA affichera un pixel rouge et un pixel bleu.

Dans un registre, il peut s'agir du nombre 65 sous forme d'entier. Faire de l'arithmétique pour régler le bit 32 pourrait signifier n'importe quoi sans contexte, mais pourrait spécifiquement changer une lettre en minuscule.

Le processeur 8086 a (encore) des instructions spéciales appelées DAA qui sont utilisées lorsque le registre contient 2 chiffres décimaux, donc si vous venez d'utiliser cette instruction, vous l'interprétez comme deux chiffres 41.

Les programmes se bloquent car un mot mémoire est lu en pensant qu'il s'agit d'un pointeur lorsque quelque chose d'autre y était stocké.

À l'aide d'un débogueur, inspectant la mémoire, une carte est utilisée pour guider l'interprétation pour l'affichage. Sans ces informations de symbole, un débogueur de bas niveau vous permet de spécifier: afficher cette adresse sous forme de mots 16 bits, afficher cette adresse sous forme de virgule flottante longue, sous forme de chaînes ... peu importe. En regardant un vidage de paquets réseau ou un format de fichier inconnu, le résoudre est un défi.

C'est une source majeure de puissance et de flexibilité dans l'architecture informatique moderne: une cellule mémoire peut signifier n'importe quoi , des données ou des instructions, implicites uniquement dans ce que cela "signifie" pour le programme par ce qu'il fait avec la valeur et comment cela affecte les opérations suivantes. la signification est plus profonde que la largeur entière: ces caractères sont-ils ... des caractères en ascii ou ebcdic? Former des mots en anglais ou en codes produits SQU? L'adresse à laquelle envoyer ou l'adresse de retour d'où il provient? L'interprétation de niveau le plus bas (bits logiques; de type entier, signé ou non signé; float; bcd; pointeur) est contextuelle au niveau du jeu d'instructions, mais vous voyez que tout est contextuel à un certain niveau: le tol'adresse est ce qu'elle est en raison de l'emplacement où elle est imprimée sur l'enveloppe. C'est contextuel aux règles du facteur, pas au CPU. Le contexte est un grand continuum, avec des bits à une extrémité.


※ Note de bas de page: l'instruction DAA est codée sous forme d'octet 00100111. Donc, cet octet est l'instruction susmentionnée si elle est lue dans le flux d'instructions, et les chiffres 27s'ils sont interprétés comme des chiffres bcd, et 0x27 = 39 comme un entier, qui est le chiffre 9 en ASCII, et une partie de la table d'interruption (la moitié de INT 13 Adresse à 2 octets, utilisée pour les routines de service du BIOS).

JDługosz
la source
1

La seule façon dont l'ordinateur sait qu'un emplacement de mémoire est une instruction est qu'un registre à usage spécial appelé pointeur d'instruction pointe vers eux à un moment ou à un autre. Si le pointeur d'instruction pointe vers un mot mémoire, il est chargé en tant qu'instruction. À part cela, l'ordinateur n'a aucun moyen de connaître la différence entre les programmes et d'autres types de données.

Dummy Dum
la source