C# Int16-在.net中的字节容量?

C# Int16-在.net中的字节容量?,c#,.net,byte,short,C#,.net,Byte,Short,为什么: short a=0; Console.Write(Marshal.SizeOf(a)); 显示2 但如果我看到IL代码,我会看到: /*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.Runti

为什么:

short a=0;
Console.Write(Marshal.SizeOf(a));
显示
2

但如果我看到IL代码,我会看到:

/*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
第1行的LDC表示:

将0作为int32推送到堆栈上

因此必须有
4个
字节被占用

但是
sizeOf
显示
2
字节

我错过了什么?short在mem中实际包含多少字节

我听说过一种情况,其中有一个4字节的填充,这样处理起来会更快。这里也是这样吗


(请忽略syncRoot和GC root标志字节,我只是想问一下2对4)

CLI规范非常明确地说明了允许在堆栈上的数据类型。短的16位整数不是其中之一,因此当这些类型的整数加载到堆栈上时,它们会转换为32位整数(4字节)

第III.1.1节包含所有详细信息:

1.1数据类型

CTS定义了一个富类型系统,CLS指定了一个子集,可以用于语言 互操作性方面,CLI本身处理一组简单得多的类型。这些类型包括用户定义的值 类型和内置类型的子集。该子集统称为“基本CLI类型”,包含 以下类型:

  • 完整数字类型的子集(
    int32
    int64
    native int
    F
  • 对象引用(
    O
    ),不区分引用的对象类型
  • 指针类型(
    native unsigned int
    &
    )不区分指向的类型
请注意,可以为对象引用和指针类型分配值
null
。这在整个CLI中定义为零(所有位为零的位模式)

1.1.1数字数据类型

  • CLI仅对数值类型
    int32
    (4字节有符号整数)、
    int64
    (8字节整数)进行操作 有符号整数),
    native int
    (本机大小整数)和
    F
    (本机大小浮点 数字)。但是,CIL指令集允许实现其他数据类型:

  • 短整数:计算堆栈只保存4字节或8字节的整数,但保存其他位置的整数 (参数、局部变量、静态、数组元素、字段)可以包含1字节或2字节的整数。对于 堆栈操作的目的bool和char类型是 分别作为无符号1字节和2字节整数处理。从这些位置加载到 堆栈通过以下方式将其转换为4字节值:

    • 无符号int8、无符号int16、bool和char类型的零扩展
    • int8和int16类型的符号扩展
    • 零扩展用于无符号间接加载和元素加载(
      ldind.u*
      ldelem.u*
      ,等等);;及
    • 符号扩展用于符号间接加载和元素加载(
      ldind.i*
      ldelem.i*
      等)
存储到整数、布尔值和字符(
stloc
stfld
stind.i1
stelem.i2
等)会截断。使用
conv.ovf.*
指令检测此截断何时会导致不正确表示原始值的值

[注:在所有体系结构上,短整数(即1字节和2字节)作为4字节数加载,并且这些4字节数始终作为与8字节数不同的数字进行跟踪。这有助于代码的可移植性,确保默认的算术行为(即,当没有执行
conv
conv.ovf
指令时)将在所有实施中产生相同的结果。]

产生短整数值的Convert指令实际上在堆栈上保留了一个
int32
(32位)值,但可以保证只有低位有意义(即,对于无符号转换,更重要的位都是零,对于有符号转换,有符号扩展)。要正确模拟全套短整数操作,需要在
div
rem
shr
、比较之前将其转换为短整数 和条件分支指令

……等等

推测地说,这个决定可能是为了架构的简单性或速度(或者两者兼而有之)。与16位整数相比,现代32位和64位处理器可以更有效地处理32位整数,而且由于可以用2个字节表示的所有整数也可以用4个字节表示,因此这种行为是合理的

使用2字节整数而不是4字节整数唯一有意义的是,如果您更关心内存使用,而不是执行速度/效率。在这种情况下,你需要有一大堆这样的值,可能被打包到一个结构中。这时您需要关心的是
marshall.SizeOf

的结果,C语言规范定义了程序的行为方式。它没有说明如何实现这一点,只要行为是正确的。如果你问一个
短码的大小,你总是会得到
2

在实践中,C#编译为CIL,其中小于32位的整数类型在stack1上表示为32位整数

然后JITer再次将其映射到适合目标硬件的任何对象,通常是堆栈上的一块内存或寄存器

只要这些转变没有改变,可见的行为就合法

在实践中,局部变量的大小在很大程度上是无关的,重要的是数组的大小。一百万个
short
s的数组通常会占用2MB


1这是IL操作的虚拟堆栈,与
box System.Int16
    byte b1 = 127;
    b1 += 1;            // no error
    b1 = b1 + 1;        // error CS0266