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