C# 有没有一种很好的方法可以将一个int拆分为两个短裤(.NET)?
我认为这是不可能的,因为C# 有没有一种很好的方法可以将一个int拆分为两个短裤(.NET)?,c#,.net,vb.net,math,C#,.net,Vb.net,Math,我认为这是不可能的,因为Int32具有1位符号和31位数字信息,而Int16具有1位符号和15位数字信息,这导致具有2位符号和30位信息 如果这是真的,那么我不能让一个Int32变成两个Int16。这是真的吗 提前谢谢 额外信息:使用Vb.Net,但我认为我可以毫无问题地翻译C#答案 最初我想做的是将一个UInt32转换为两个UInt16,因为这是一个与基于单词的机器交互的库。然后我意识到Uint不符合CLS,并尝试对Int32和Int16执行同样的操作 更糟糕的是:做a=CType(c和&HF
Int32
具有1位符号和31位数字信息,而Int16具有1位符号和15位数字信息,这导致具有2位符号和30位信息
如果这是真的,那么我不能让一个Int32
变成两个Int16
。这是真的吗
提前谢谢
额外信息:使用Vb.Net,但我认为我可以毫无问题地翻译C#答案
最初我想做的是将一个UInt32
转换为两个UInt16
,因为这是一个与基于单词的机器交互的库。然后我意识到Uint
不符合CLS,并尝试对Int32
和Int16
执行同样的操作
更糟糕的是:做
a=CType(c和&HFFFF,Int16)代码>抛出溢出异常
。我希望该语句与a=(Int16)(c&0xffff)相同代码>(不会引发异常)。由于存储宽度(32位和16位),如果您的Int32大于32767,则将Int32转换为Int16可能意味着信息丢失。是的,可以使用掩蔽和位移位来完成
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);
int16a,b;
Int32 c=-1;
a=(Int16)(c&0xffff);
b=(Int16)((c>>16)和0xffff);
Int32重建=((Int32)a)和0xffff)|((Int32)b如果您查看位表示,那么您是正确的
不过,您可以对无符号整数执行此操作,因为它们没有符号位。这当然可以在不丢失信息的情况下完成。在这两种情况下,您都会得到32位信息。它们是否用于符号位无关紧要:
int original = ...;
short firstHalf = (short) (original >> 16);
short secondHalf = (short) (original & 0xffff);
int reconstituted = (firstHalf << 16) | (secondHalf & 0xffff);
int-original=。。。;
短上半段=(短)(原始>>16);
短后半部分=(短)(原始和0xffff);
int restructured=(firstHalf为什么不呢?为了简单起见,让我们减少位的数量:假设我们有8位,其中左位是负位
[1001 0110] // representing -22
您可以将其存储为2乘以4位
[1001] [0110] // representing -1 and 6
我不明白为什么不可能,你有两次8位信息
编辑:为了简单起见,我不仅减少了位,而且也不使用2互补方法。在我的例子中,左边的位表示减数,剩下的被解释为正的正数二进制数
如果使用C++,你可能对结构布局或联合感兴趣。
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);
,已翻译为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
在.NETCType(&Hffff,Int16)
中会导致溢出,而(short)0xffff
会给出-1(无溢出)。这是因为默认情况下,C#编译器使用未经检查的操作,而VB.NET已检查
就我个人而言,我喜欢,因为我的代码更复杂,而Jon的代码会在checked环境中导致溢出异常
我还基于BitConverter类的代码对此特定任务进行了优化。但是,它使用了不安全的代码。您可以在VB.NET中使用StructLayout:
更正:字是16位,dword是32位
_
公共结构UDWord
作为UInt32的公共价值
公共高等教育学院(UInt16)
公共低至UInt16
公共子新建(ByVal值为UInt32)
价值=价值
端接头
公共子新建(ByVal高达UInt16,ByVal低达UInt16)
我高
Me.Low=低
端接头
端部结构
只需使用这些类型就可以了
<StructLayout(LayoutKind.Explicit, Size:=4)> _
Public Structure DWord
<FieldOffset(0)> Public Value As Int32
<FieldOffset(0)> Public High As Int16
<FieldOffset(2)> 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
_
公共结构德沃德
Int32的公共价值
公营高达国际16
公众低至国际16
Public Sub New(ByVal值为Int32)
价值=价值
端接头
新公共子系统(ByVal高达Int16,ByVal低达Int16)
我高
Me.Low=低
端接头
端部结构
编辑:
我发布/编辑我的anwser的几次都有点匆忙,还没有解释这个解决方案,所以我觉得我还没有完成我的答案。所以我现在就要这么做:
将StructLayout显式用于结构需要使用FieldOffset属性提供每个字段的位置(按字节偏移)
使用这两个属性可以创建重叠字段,即
第一个字段(DWord.Value)将是偏移量为0(零)的32位整数。若要拆分此32位整数,您将有两个额外的字段,从偏移量为0(零)开始,然后第二个字段再减去2个字节,因为16位(短)整数是2个字节a-peice
据我回忆,通常当你拆分一个整数时,他们通常会将前半部分称为“高”,然后将后半部分称为“低”;这样,我的另外两个字段就被命名为“低”
通过使用这样的结构,您可以为运算符创建重载,并键入widing/Nerrowing,以便轻松地从例如Int32类型交换到此DWord结构,以及比较C#中的不安全代码,不会发生溢出,自动检测endianness:
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])
};
}
}
}
使用系统;
班级计划
{
静态void Main(字符串[]参数)
{
选中//是,它工作时不会溢出!
{
Int32原始值=Int32.MaxValue;
Int16[]结果=GetShorts(原始);
WriteLine(“原始int:{0:x}”,原始);
WriteLine(“高级Int16:{0:x}”,结果[1]);
WriteLine(“Junior Int16:{0:x}”,结果[0]);
Console.ReadKey();
}
}
静态不安全Int16[]GetShorts(Int32值)
{
字节[]缓冲区=新字节[4];
固定(字节*numRef=缓冲区)
{
*((Int32*)numRef)=值;
if(位转换器.IsLittleEndian)
返回新的Int16[]{*((Int16*)numRef),*((Int16*)numRef+1)};
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])
};
}
}
}
[StructLayout(LayoutKind.Explicit)]
struct Helper
{
[FieldOffset(0)]
public int Value;
[FieldOffset(0)]
public short Low;
[FieldOffset(2)]
public short High;
}
var helper = new Helper {value = 12345};
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
}
public (ushort, ushort) SplitToUnsignedShorts(uint value)
{
ushort v1 = (ushort) (value / 0x10000);
ushort v2 = (ushort) (value % 0x10000);
return (v1, v2);
}
public (ushort, ushort) SplitToUShorts(uint value)
=> ((ushort)(value / 0x10000), (ushort)(value % 0x10000));