有没有一种很好的方法将int分成两个短裤(.NET)?

我认为这是不可能的,因为Int32有1位符号并且有31位数字信息而Int16有1位符号和15位数字信息,这导致有2位符号和30位信息。

如果这是真的那么我就不能将一个Int32分成两个Int16 。 这是真的?

提前致谢。

附加信息:使用Vb.Net,但我认为我可以毫无问题地翻译C#答案。

我最初想要做的是将一个UInt32转换为两个UInt16因为这是一个与基于WORD的机器交互的库。 然后我意识到Uint不符合CLS,并试图用Int32Int16做同样的事情。

EVEN WORSE:做a = CType(c And &HFFFF, Int16); 抛出OverflowException 。 我期望该陈述与a = (Int16)(c & 0xffff); (不会抛出exception)。

这应该工作:

 int original = ...; byte[] bytes = BitConverter.GetBytes(original); short firstHalf = BitConverter.ToInt16(bytes, 0); short secondHalf = BitConverter.ToInt16(bytes, 2); 

编辑:

用0x7FFFFFFF测试,它的工作原理

 byte[] recbytes = new byte[4]; recbytes[0] = BitConverter.GetBytes(firstHalf)[0]; recbytes[1] = BitConverter.GetBytes(firstHalf)[1]; recbytes[2] = BitConverter.GetBytes(secondHalf)[0]; recbytes[3] = BitConverter.GetBytes(secondHalf)[1]; int reconstituted = BitConverter.ToInt32(recbytes, 0); 

这当然可以在不丢失信息的情况下完成。 在这两种情况下,最终都会得到32位信息。 它们是否用于符号位是无关紧要的:

 int original = ...; short firstHalf = (short) (original >> 16); short secondHalf = (short) (original & 0xffff); int reconstituted = (firstHalf << 16) | (secondHalf & 0xffff); 

在这里, reconstituted将始终等于original ,因此没有信息丢失。

现在两个短路的符号的含义是另一回事 - 如果original是负的,则secondHalf是负的,如果设置original 15位(计数0-31),则secondHalf将是负的,这在原始forms。

Jon的答案 ,翻译成Visual Basic,没有溢出:

 Module Module1 Function MakeSigned(ByVal x As UInt16) As Int16 Dim juniorBits As Int16 = CType(x And &H7FFF, Int16) If x > Int16.MaxValue Then Return juniorBits + Int16.MinValue End If Return juniorBits End Function Sub Main() Dim original As Int32 = &H7FFFFFFF Dim firstHalfUnsigned As UInt16 = CType(original >> 16, UInt16) Dim secondHalfUnsigned As UInt16 = CType(original And &HFFFF, UInt16) Dim firstHalfSigned As Int16 = MakeSigned(firstHalfUnsigned) Dim secondHalfSigned As Int16 = MakeSigned(secondHalfUnsigned) Console.WriteLine(firstHalfUnsigned) Console.WriteLine(secondHalfUnsigned) Console.WriteLine(firstHalfSigned) Console.WriteLine(secondHalfSigned) End Sub End Module 

结果:

 32767 65535 32767 -1 

在.NET中, CType(&Hffff, Int16)导致溢出,而(short)0xffff导致-1(没有溢出)。 这是因为默认情况下C#编译器使用未经检查的操作并检查VB.NET。

我个人喜欢Agg的答案 ,因为我的代码更复杂,而且Jon会在检查环境中导致溢出exception。

我还根据BitConverter类的代码创建了另一个答案 ,针对此特定任务进行了优化。 但是,它使用不安全的代码。

是的,它可以使用掩蔽和位移来完成

  Int16 a,b; Int32 c; a = (Int16) (c&0xffff); b = (Int16) ((c>>16)&0xffff); 

编辑

回答评论。 重建工作正常:

  Int16 a, b; Int32 c = -1; a = (Int16)(c & 0xffff); b = (Int16)((c >> 16) & 0xffff); Int32 reconst = (((Int32)a)&0xffff) | ((Int32)b << 16); Console.WriteLine("reconst = " + reconst); 

测试它并按预期打印-1。

EDIT2:改变了重建。 Int16到Int32的升级导致所有符号位扩展。 忘了,它必须是AND'ed。

为什么不? 为简单起见,让我们减少位数:假设我们有8位,其中左位是负位。

 [1001 0110] // representing -22 

您可以将其存储在2位4位中

 [1001] [0110] // representing -1 and 6 

我不明白为什么它不可能,你两次有8位信息

编辑:为了简单起见,我不仅减少了比特,还不使用2补码方法。 在我的例子中,左边的比特表示减号,其余部分被解释为正常的正二进制数

C#中的不安全代码,不会发生溢出,自动检测字节序:

 using System; class Program { static void Main(String[] args) { checked // Yes, it works without overflow! { Int32 original = Int32.MaxValue; Int16[] result = GetShorts(original); Console.WriteLine("Original int: {0:x}", original); Console.WriteLine("Senior Int16: {0:x}", result[1]); Console.WriteLine("Junior Int16: {0:x}", result[0]); Console.ReadKey(); } } static unsafe Int16[] GetShorts(Int32 value) { byte[] buffer = new byte[4]; fixed (byte* numRef = buffer) { *((Int32*)numRef) = value; if (BitConverter.IsLittleEndian) return new Int16[] { *((Int16*)numRef), *((Int16*)numRef + 1) }; return new Int16[] { (Int16)((numRef[0] << 8) | numRef[1]), (Int16)((numRef[2] << 8) | numRef[3]) }; } } } 

您可以在VB.NET中使用StructLayout:

校正:字是16bit,dword是32bit

  _ Public Structure UDWord  Public Value As UInt32  Public High As UInt16  Public Low As UInt16 Public Sub New(ByVal value As UInt32) Me.Value = value End Sub Public Sub New(ByVal high as UInt16, ByVal low as UInt16) Me.High = high Me.Low = low End Sub End Structure 

签名将使用这些类型相同

  _ Public Structure DWord  Public Value As Int32  Public High As Int16  Public Low As Int16 Public Sub New(ByVal value As Int32) Me.Value = value End Sub Public Sub New(ByVal high as Int16, ByVal low as Int16) Me.High = high Me.Low = low End Sub End Structure 

编辑:

我有点匆匆几次发布/编辑我的anwser,然后解释这个解决方案,所以我觉得我还没有完成我的答案。 所以我现在要这样做:

将StructLayout显式化为结构需要您使用FieldOffset属性[FieldOffsetAttribute]提供每个字段的定位(按字节偏移量) [StructLayoutAttribute ]

使用这两个属性,您可以创建重叠字段,即联合 。

第一个字段(DWord.Value)是32位整数,偏移量为0(零)。 要分割这个32位整数,你将有两个额外的字段再次从0(零)的偏移开始,然后第二个字段2更多的字节关闭,因为16位(短)整数是2字节a-peice。

从我记得的情况来看,通常当你分裂一个整数时,他们通常将前半部分称为“高”,然后将下半部分称为“低”; 从而命名我的另外两个领域。

通过使用这样的结构,您可以为运算符创建重载并输入widing / narrowing,以便从Int32类型轻松交换到此DWord结构,以及在VB.NET中运算符重载

您可以使用StructLayout执行此操作:

 [StructLayout(LayoutKind.Explicit)] struct Helper { [FieldOffset(0)] public int Value; [FieldOffset(0)] public short Low; [FieldOffset(2)] public short High; } 

使用它,您可以获得完整的值作为int,而低的部分,高的部分作为短。

就像是:

 var helper = new Helper {value = 12345}; 

由于存储宽度(32位和16位),如果Int32大于32767,将Int32转换为Int16可能意味着丢失信息。

如果你看一下比特表示,那你就是对的。

你可以使用无符号整数执行此操作,因为它们没有符号位。

如果您正在使用c ++,您可能也对StructLayout或联合感兴趣。

Int32 num = 70000;

  string str = Convert.ToString(num, 2); //convert INT32 to Binary string Int32 strl = str.Length; //detect string length string strhi, strlo; //ifvalue is greater than 16 bit if (strl > 16) { int lg = strl - 16; //dtect bits in higher word strlo = str.Substring(lg, 16); ///move lower word string to strlo strhi = str.Substring(0, lg); //mov higher word string to strhi } else //if value is less than 16 bit { strhi = "0"; //set higher word zero strlo = str; ///move lower word string to strlo } Int16 lowword, hiword; lowword = Convert.ToInt16(strlo, 2); hiword = Convert.ToInt16(strhi, 2); ////convert binary string to int16 }