Pourquoi: montre mais si je vois le code IL, je vois: p> 2 code> 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
4 Réponses :
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. P>
Partition III.1.1 contient tous les détails: P>
1.1 Types de données strong> P>
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: P>
- Un sous-ensemble des types numériques complets (
int32 code>,
int64 code>,
native int code> et
f code>). li>
- Références d'objet (
O code>) sans distinction entre le type d'objet référencé. LI>
- Types de pointer (
Native non signé INT code> et
& code>) sans distinction sur le type pointé sur. li> ul>
Notez que les références d'objet et les types de pointeurs peuvent être attribués à la valeur
null code>. Ceci est défini dans tout le CLI à être zéro (un motif de bits de tous les bits-zéro). P>
1.1.1 Types de données numériques strong> p>
Le CLI fonctionne uniquement sur les types numériques
int32 code> (4 octets signé des entiers),
int64 code> (8 octets entiers signés),
native int code> (entiers de taille natif) et
f code> (point flottant de taille natif Nombres). Cependant, l'ensemble d'instructions CIL permet d'implémenter des types de données supplémentaires: P> li>
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: p>
- s'étend sur zéro pour les types non signés Int8, non signé Int16, Bool et Char; Li>
- Signature s'étendant pour les types INT8 et INT16; LI>
- zéro s'étend pour des charges indirectes et d'éléments non signés (
ldind.u * code>,
ldelem.u * code>, etc.) ;; et li>
- Sign-Signend-s'étend pour des charges indirectes et d'éléments signées (
ldind.i * code>,
ldelem.i * code>, etc.) li> ul> li> ul>
Stockage en entiers, booléens et caractères (
stloc code>,
stfld code>,
staind.i1 code>,
stelem.i2 code >, etc.) tronque. Utilisez les instructions
conv.ovf. * Code> pour détecter lorsque cette troncature entraîne une valeur qui ne représente pas correctement la valeur d'origine. P>
[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 code> ou
CONV.OVF code> est exécuté) aura des résultats identiques sur toutes les implémentations.] < / em> p>
Convertissez des instructions qui produisent des valeurs entières courtes laissant une valeur
int32 code> (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 code>,
REM code>,
SHR code>, comparaison Instructions de branche conditionnelle. P> blockQuote>
... et ainsi de suite. P>
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 . p>
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 code>. P>
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 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 p>. p>.
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. P>
Tant que rien de ces transformations ne change La taille de la pratique des variables locales est largement pertinente, ce qui compte est la taille des matrices. Un tableau d'un million 1 sup> 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. p> court code>, vous obtenez toujours
2 code>. P>
court code> S occupera habituellement 2 Mo. P>
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
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 forte> 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. P> 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. P> 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 em>. 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. P> 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 #: p> 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 em> 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 em> 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. P> P>
Hans, "int, long, flotteur et double" i> - Qu'en est-il du seul type qui peut représenter un nombre décimal précis pur ( décimal code>)? 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.
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 code> entièrement et simplement utiliser une constante
2 code> à la place.