我认为这是不可能的,因为Int32
有1位符号并且有31位数字信息而Int16有1位符号和15位数字信息,这导致有2位符号和30位信息。
如果这是真的,那么我不能将Int32
合并为两个Int16
。这是真的吗?
提前致谢。
额外信息:使用Vb.Net,但我认为我可以毫无问题地翻译C#答案。
我最初想要做的是将一个UInt32
转换为两个UInt16
,因为这是一个与基于WORD的计算机交互的库。然后我意识到Uint
不符合CLS,并尝试对Int32
和Int16
执行相同操作。
EVEN WORSE:执行a = CType(c And &HFFFF, Int16);
投掷OverflowException
。我希望该语句与a = (Int16)(c & 0xffff);
相同(不会抛出异常)。
答案 0 :(得分:36)
这当然可以在不丢失信息的情况下完成。在这两种情况下,最终都会得到32位信息。它们是否用于符号位是无关紧要的:
int original = ...;
short firstHalf = (short) (original >> 16);
short secondHalf = (short) (original & 0xffff);
int reconstituted = (firstHalf << 16) | (secondHalf & 0xffff);
此处,reconstituted
将始终等于original
,因此不会丢失任何信息。
现在意味着这两条短路的标志是另一回事 - 如果firstHalf
为负,original
将为负,但secondHalf
将是如果设置original
的第15位(计数0-31),则为负数,这在原始形式中没有特别的意义。
答案 1 :(得分:12)
这应该有效:
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);
答案 2 :(得分:7)
Jon's answer,翻译成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's answer,因为我的代码更复杂,而Jon会在已检查环境中导致溢出异常。
我还created another answer,基于BitConverter
类的代码,针对此特定任务进行了优化。但是,它使用不安全的代码。
答案 3 :(得分:4)
是的,可以使用屏蔽和位移来完成
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。
答案 4 :(得分:3)
为什么不呢?为简单起见,让我们减少位数:假设我们有8位,其中左位是负位。
[1001 0110] // representing -22
您可以将其存储为2次4位
[1001] [0110] // representing -1 and 6
我不明白为什么不可能,你两次有8位信息
编辑:为了简单起见,我不仅减少了比特,而且还不使用2补码方法。在我的例子中,左边的比特表示减号,其余部分被解释为正常的正二进制数
答案 5 :(得分:2)
您可以在VB.NET中使用StructLayout:
更正:字是16位,dword是32位
<StructLayout(LayoutKind.Explicit, Size:=4)> _
Public Structure UDWord
<FieldOffset(0)> Public Value As UInt32
<FieldOffset(0)> Public High As UInt16
<FieldOffset(2)> 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
签名与使用这些类型相同
<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
修改强>
我有点匆匆几次发布/编辑我的anwser,然后解释这个解决方案,所以我觉得我还没有完成我的答案。所以我现在要这样做:
将StructLayout显式地用于结构需要您使用FieldOffset属性[StructLayoutAttribute]
提供每个字段(按字节偏移量)[FieldOffsetAttribute]的定位使用这两个属性,您可以创建重叠字段,即unions。
第一个字段(DWord.Value)是32位整数,偏移量为0(零)。要分割这个32位整数,你将有两个额外的字段从0(零)的偏移量再次开始,然后第二个字段2个字节关闭,因为16位(短)整数是2字节a-peice。
从我记得的情况来看,通常当你分割一个整数时,他们通常将前半部分称为“高”,然后将下半部分称为“低”;从而命名我的另外两个领域。
通过使用这样的结构,您可以为运算符创建重载并输入widing / narrowing,以便轻松地从Int32类型交换到此DWord结构,以及比较Operator Overloading in VB.NET
答案 6 :(得分: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])
};
}
}
}
答案 7 :(得分:2)
您可以使用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};
答案 8 :(得分:0)
由于存储宽度(32位和16位),如果Int32大于32767,将Int32转换为Int16可能意味着丢失信息。
答案 9 :(得分:0)
如果查看位表示,那么你是对的。
你可以使用无符号整数执行此操作,因为它们没有符号位。
答案 10 :(得分:0)
如果你正在使用c ++,你可能也对StructLayout或工会感兴趣。
答案 11 :(得分:0)
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
}
答案 12 :(得分:0)
我没有使用按位运算符,但对于无符号值,这可能有效:
mydata = [{'stock_symbol': 'ALT', 'shares_total': 1, 'Price': 12.29}, {'stock_symbol': 'NFLX', 'shares_total': 5, 'Price': 534.5}]
stock_symbol=[]
shares_total=[]
price=[]
# start loop
for data in mydata:
stock_symbol.append(data['stock_symbol'])
shares_total.append(data['shares_total'])
price.append(data['Price'])
或者它的表达式主体版本:
public (ushort, ushort) SplitToUnsignedShorts(uint value)
{
ushort v1 = (ushort) (value / 0x10000);
ushort v2 = (ushort) (value % 0x10000);
return (v1, v2);
}
至于符号,您必须决定如何拆分数据。两个负输出只能有 1 个。请记住,有符号值总是牺牲一位来存储数字的负状态。这基本上将您在该变量中可以拥有的最大值“减半”。这也是为什么uint可以存储两倍于signed int的原因。
至于将其编码为您的目标格式,您可以选择将第二个数字设为无符号短整型以保留数值,或者您可以手动对其进行编码,以便现在一位代表该值的符号。这样,虽然您会丢失符号位的最初预期数值,但您不会丢失原始二进制数据,并且您始终可以将其重建为原始值。
最终归结为您希望如何存储和处理该数据。只要您知道如何从(或合并到)您的编码值中提取数据,您就不会丢失比特,进而丢失数据。