6
votes

Int16 - capacité d'octets in.net?

Pourquoi: xxx pré>

montre 2 code> p>

mais si je vois le code IL, je vois: p>

/*1*/   IL_0000:  ldc.i4.0    
/*2*/   IL_0001:  stloc.0     
/*3*/   IL_0002:  ldloc.0     
/*4*/   IL_0003:  box         System.Int16
/*5*/   IL_0008:  call        System.Runtime.InteropServices.Marshal.SizeOf
/*6*/   IL_000D:  call        System.Console.Write


3 commentaires

La taille en mémoire n'est qu'un concept significatif lorsque vous l'avez intégré dans une structure plus grande, par exemple dans un tableau. Lorsque vous avez une variable locale, cela occupe généralement un registre complet (64 bits sur AMD64), même s'il s'agit d'un seul octet. Le compilateur C # utilise Int32 en interne pour la plupart des choses, ce qui est dans ses droits aussi longtemps que le comportement observé correspond à celui d'une INT16.


@Codesinchaos de sorte qu'il faut 4 octets en 32 bits? Et si oui, pourquoi Sieof montre 2?


La taille est 2 car elle est définie comme ça, et 2 octets sont suffisants. Mais si vous avez une variable locale, il faut autant d'octets que le compilateur / Jiter souhaite. Tant que le comportement du programme n'est pas affecté, ils sont libres de faire ce qu'ils aiment. Souvent, une seule variable locale est stockée dans différents endroits pendant la course d'une méthode. Dans votre cas, ils pourraient même éliminer un entièrement et simplement utiliser une constante 2 à la place.


4 Réponses :


7
votes

La spécification CLI est très explicite sur les types de données qui sont autorisés à être sur la pile. L'entier court 16 bits n'est pas l'un d'entre eux, de sorte que de tels types d'entiers sont convertis en entiers 32 bits (4 octets) lorsqu'ils sont chargés sur la pile.

Partition III.1.1 contient tous les détails:

1.1 Types de données

Bien que le CTS définit un système de type riche et que les CLS spécifient un sous-ensemble pouvant être utilisé pour la langue. Interopérabilité, la CLI elle-même traite d'un ensemble de types beaucoup plus simples. Ces types incluent la valeur définie par l'utilisateur types et un sous-ensemble des types intégrés. Le sous-ensemble, appelé collectivement appelé les "types de base de cli", contient le Types suivants:

  • Un sous-ensemble des types numériques complets ( int32 , int64 , native int et f ).
  • Références d'objet ( O ) sans distinction entre le type d'objet référencé.
  • Types de pointer ( Native non signé INT et & ) sans distinction sur le type pointé sur.

    Notez que les références d'objet et les types de pointeurs peuvent être attribués à la valeur null . Ceci est défini dans tout le CLI à être zéro (un motif de bits de tous les bits-zéro).

    1.1.1 Types de données numériques

    • Le CLI fonctionne uniquement sur les types numériques int32 (4 octets signé des entiers), int64 (8 octets entiers signés), native int (entiers de taille natif) et f (point flottant de taille natif Nombres). Cependant, l'ensemble d'instructions CIL permet d'implémenter des types de données supplémentaires:

    • complets courts: la pile d'évaluation ne contient que des entiers de 4 ou 8 octets, mais d'autres emplacements (Arguments, variables locales, statiques, éléments de tableau, champs) peuvent contenir des entiers de 1 ou 2 octets. Pour le Objet des opérations de pile Les types Bool et Char sont traité comme des entiers de 1 octets non signés et de 2 octets respectivement. Chargement à partir de ces endroits sur le Stack les convertit aux valeurs de 4 octets par:

      • s'étend sur zéro pour les types non signés Int8, non signé Int16, Bool et Char;
      • Signature s'étendant pour les types INT8 et INT16;
      • zéro s'étend pour des charges indirectes et d'éléments non signés ( ldind.u * , ldelem.u * , etc.) ;; et
      • Sign-Signend-s'étend pour des charges indirectes et d'éléments signées ( ldind.i * , ldelem.i * , etc.)

        Stockage en entiers, booléens et caractères ( stloc , stfld , staind.i1 , stelem.i2 , etc.) tronque. Utilisez les instructions conv.ovf. * pour détecter lorsque cette troncature entraîne une valeur qui ne représente pas correctement la valeur d'origine.

        [Note: Short (I.E., 1- et 2 octets) Les entiers sont chargés sous forme de numéros de 4 octets sur toutes les architectures et ces numéros de 4 octets sont toujours suivis à partir de numéros de 8 octets. Cela aide la portabilité du code en veillant à ce que le comportement arithmétique par défaut (c'est-à-dire quand aucun CONV ou CONV.OVF est exécuté) aura des résultats identiques sur toutes les implémentations.] < / em>

        Convertissez des instructions qui produisent des valeurs entières courtes laissant une valeur int32 (32 bits) sur la pile, mais il est garanti que seuls les bits faibles ont une signification (c.-à-d. Les bits les plus importants sont Tous zéro pour les conversions non signées ou une extension de signe pour les conversions signées). Pour simuler correctement l'ensemble complet d'opérations entier courtes, une conversion en un entier court est requise avant le div , REM , SHR , comparaison Instructions de branche conditionnelle.

        ... et ainsi de suite.

        Parler de manière spéculativement, cette décision a probablement été faite soit pour la simplicité architecturale, soit pour la vitesse (ou éventuellement). Les processeurs modernes 32 bits et 64 bits peuvent travailler plus efficacement avec des entiers 32 bits qu'avec des entiers de 16 bits, et que tous les entiers pouvant être représentés dans 2 octets peuvent également être représentés dans 4 octets, ce comportement est raisonnable .

        La seule fois, il serait vraiment logique d'utiliser un entier de 2 octets par opposition à un octet d'une 4 octet, si vous étiez plus préoccupé par une utilisation de la mémoire que vous n'étiez une vitesse / efficacité d'exécution. Et dans ce cas, vous auriez besoin d'avoir un tas de ces valeurs, probablement emballé dans une structure. Et c'est à ce moment-là que vous vous souciez du résultat de maréchal.sizeof .


0 commentaires

1
votes

La spécification de langue C # définit la manière dont un programme devrait se comporter. Cela ne dit pas comment implémenter cela, tant que le comportement est correct. Si vous demandez la taille d'un court , vous obtenez toujours 2 .

En pratique C # compile en CIL, où des types intégrés inférieurs à 32 bits sont représentés sous forme d'entiers 32 bits sur la pile 1 . .

Ensuite, le jiteur le remède à nouveau sur tout ce qui est approprié pour le matériel cible, typiquement un morceau de mémoire sur la pile ou un registre.

Tant que rien de ces transformations ne change comportement observable ils sont légaux.

La taille de la pratique des variables locales est largement pertinente, ce qui compte est la taille des matrices. Un tableau d'un million court S occupera habituellement 2 Mo.


1 Il s'agit d'une pile virtuelle que l'IL fonctionne sur, qui est différente de la pile les opérations de code de machine sur.


0 commentaires

1
votes

CLR fonctionne de manière native avec des entiers 32 bits et 64 bits sur la pile. La réponse réside dans cette instruction:

box System.Int16


0 commentaires

5
votes

Il est assez facile de dire ce qui se passe en regardant le Instructions de LDC disponibles . Notez que l'ensemble limité des types d'opérande disponibles, il est N ° de version disponible pour charger une constante de type courte. Juste int, long, flotter et double. Ces limitations sont visibles ailleurs, l'instruction OPCODES.ADD par exemple est similaire limitée, aucun support pour ajouter des variables d'un des types plus petits.

L'ensemble d'instructions Il a été très conçu intentionnellement de cette façon, il reflète les capacités d'un Simple processeur 32 bits. Le type de processeur à penser est le type de RISC, ils avaient leur foin au nineteens. Beaucoup de registres de processeurs 32 bits qui ne peuvent manipuler que des entiers 32 bits et des types de points flottants IEEE-754. Le noyau Intel X86 n'est pas un bon exemple, tout en couramment utilisé, il s'agit d'une conception de la CISC qui soutient en réalité le chargement et la fabrication arithmétique sur des opérandes de 8 bits et 16 bits. Mais c'est plus un accident historique, il a fabriqué une traduction mécanique des programmes qui a été mis au point sur les processeurs 8080 et 16 bits 8 bits 8086. Mais une telle capacité ne vient pas gratuitement, la manipulation de valeurs de 16 bits coûte réellement un cycle de processeur supplémentaire.

Faire une bonne correspondance avec des capacités de processeur 32 bits rend clairement le travail du gars mettant en œuvre une gale beaucoup plus simple. Les emplacements de stockage peuvent toujours être une taille plus petite, mais uniquement des charges, des magasins et des conversions doivent être pris en charge. Et ce n'est que lorsque vous avez besoin, votre variable «A» est une variable locale qui occupe une variable 32 bits sur le cadre de la pile ou le registre CPU de toute façon. Seuls les magasins à la mémoire doivent être tronqués à la bonne taille.

Il n'y a aucune ambiguïté dans l'extrait de code. La valeur variable doit être en boîte car marshal.sizeof () prend un argument de type objet . La valeur en boîte identifie le type de valeur par la poignée de type, elle pointera sur System.int16. Marshal.SizeOf () a la connaissance intégrée de savoir qu'il faut 2 octets.

Ces restrictions reflètent la langue C # et causer une incohérence. Ce type d'erreur de compilation pour toujours des favoris et gêne les programmeurs C #: xxx

résultat des restrictions IL, il n'y a pas d'opérateur supplémentaire qui prend des opérandes d'octets. Ils doivent être convertis au plus grand type compatible, int dans ce cas. Cela fonctionne donc sur un processeur de RISC 32 bits. Maintenant, il y a un problème, le résultat 32 bits int doit être martelé dans une variable pouvant stocker seulement 8 bits. La langue C # s'applique que le marteau lui-même dans la 1ère affectation mais nécessite un marteau moulé dans la 2e affectation.


2 commentaires

Hans, "int, long, flotteur et double" - Qu'en est-il du seul type qui peut représenter un nombre décimal précis pur ( décimal )? Comment ça va ici ici? Merci. (P.S. J'ai adoré la structure de réponse: histoire, présent, exemple.)


Le CLR n'a aucune connaissance particulière de System.Decimal, seul le compilateur fait. Au CLR, c'est juste un type de structure ordinaire.