我希望能够将高值无符号整数(使用最高位的值)转换为有符号整数。在这种情况下,我不关心该值是否高于有符号整数类型的最大值。我只是希望它转换为位值表示的有符号整数。换句话说,我希望它会导致负数。
但是,使用VB.NET时,CType
操作无法正常工作(或任何其他转换函数,如CShort
和CInteger
)。当您尝试转换高于所需签名类型的最大值的无符号值时,它会抛出OverflowException
而不是返回负数。例如:
Dim x As UShort = UShort.MaxValue
Dim y As Short = CShort(x) ' Throws OverflowException
值得一提的是,DirectCast
操作不能用于在有符号和无符号类型之间转换值,因为这两种类型都不继承或实现另一种类型。例如:
Dim x As UShort = UShort.MaxValue
Dim y As Short = DirectCast(x, Short) ' Won't compile: "Value of type 'UShort' cannot be converted to 'Short'
我已经找到了一种方法来做我想做的事情,但它似乎不必要地丑陋。以下是我如何使用它:
Dim x As UShort = UShort.MaxValue
Dim y As Short = BitConverter.ToInt16(BitConverter.GetBytes(x), 0) ' y gets set to -1
就像我说的那样,但是如果在VB.NET中有一种更简单,更清晰的方式,我很想知道它是什么。
答案 0 :(得分:13)
如果你经常使用BitConverter
,那么unchecked
的使用会有点不方便 - 特别是对于性能。如果那是我,我会非常想在C#中添加一个可以直接转换的实用程序库(通过unchecked
,尽管[StructLayout(LayoutKind.Explicit)]
struct EvilUnion
{
[FieldOffset(0)] public int Int32;
[FieldOffset(0)] public uint UInt32;
}
...
var evil = new EvilUnion();
evil.Int32 = -123;
var converted = evil.UInt32;
通常是C#中的默认值 ),并为此引用该库。另一种选择可能是滥用“联盟”结构;以下内容应该很容易转换为VB:
<System.Runtime.InteropServices.StructLayout(Runtime.InteropServices.LayoutKind.Explicit)>
Structure EvilUnion
<System.Runtime.InteropServices.FieldOffset(0)>
Public Int32 As Integer
<System.Runtime.InteropServices.FieldOffset(0)>
Public UInt32 As UInteger
End Structure
...
Dim evil As New EvilUnion
evil.Int32 = -123
Dim converted = evil.UInt32
即
{{1}}
答案 1 :(得分:2)
回到VB6时代,我们不得不一直编写这样的例程:
Private Function ToShort(ByVal us As UShort) As Short
If (us And &H8000) = 0 Then
Return CType(us, Short)
Else
Return CType(CType(us, Integer) - UShort.MaxValue - 1, Short)
End If
End Function
至少在.NET中,你可以创建一个扩展方法,通过
使其更好答案 2 :(得分:2)
很简单:
Dim uVal32 As UInt32 = 3000000000
Dim Val32 As Int32 = Convert.ToInt32(uVal32.ToString("X8"), 16)
val32结束= -1294967296
Dim uVal16 As UInt16 = 60000
Dim Val16 As Int16 = Convert.ToInt16(uVal16.ToString("X4"), 16)
val16结束= -5536
答案 3 :(得分:2)
我发现了这个: ??problems typecasting in VB.NET??
大约一半的页面是这样的:
旧的,VB&#34;正确&#34; &#34; side-stepping&#34;出十六进制和 又回来了!
Dim unsigned as UInt16 = 40000
Dim signed as Int16 = CShort(Val("&H" & Hex(unsigned)))
它看起来很漂亮!
答案 4 :(得分:1)
我认为最简单的方法如下:
Public Function PutSign(ByVal number As UShort) As Short
If number > 32768 Then 'negative number
Return (65536 - number) * -1
Else
Return number
End If
End Function
答案 5 :(得分:1)
我刚刚面对这个问题并且不喜欢BitConverter方法,因为它似乎没有得到很好的优化。 所以,我认为内存中的数据存储对于int和uint来说实际上只有4个字节。
以下似乎是处理此问题的最有效方法,适用于可以使用Marshal类的所有.NET语言...
[New LWP 4684]
[New LWP 4683]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `python grview_qt5.py'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00007f5233393e69 in ?? ()
(gdb) bt
#0 0x00007f5233393e69 in ()
#1 0x00007f522fee6f20 in ()
#2 0x0000000000e0d340 in ()
#3 0x00007f522fee6f20 in ()
#4 0x0000000000e0d5f0 in ()
#5 0x00007f523e0bc000 in _rtld_local () at /lib64/ld-linux-x86-64.so.2
#6 0x00007f523ae7285f in QThreadPrivate::start(void*) (arg=0xe0d340) at thread/qthread_unix.cpp:337
#7 0x00007f523d8780a4 in start_thread (arg=0x7f522fee7700) at pthread_create.c:309
#8 0x00007f523d5adcbd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
(gdb) info threads
Id Target Id Frame
2 Thread 0x7f523e06f700 (LWP 4683) 0x00007f523deb21c7 in munmap () at ../sysdeps/unix/syscall-template.S:81
* 1 Thread 0x7f522fee7700 (LWP 4684) 0x00007f5233393e69 in ?? ()
希望这有助于某人。
答案 6 :(得分:1)
通常,这将使用更高级语言的流完成,但.Net框架使用Marshal公开了一种没有中间流对象的方法。
Imports System.Runtime.InteropServices
Module Module1
Sub Main()
Dim given As Int16 = -20
Dim buffer As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(given))
Marshal.StructureToPtr(given, buffer, False)
Dim result As UInt16 = Marshal.PtrToStructure(buffer, GetType(UInt16))
MsgBox(result)
End Sub
End Module
令我惊讶的是,根据我得到的统计数据,使用Marshal似乎比使用Math更有效
4 seconds of v1 yielded: 2358173 conversions
4 seconds of v2 yielded: 4069878 conversions
来自测试:
Imports System.Runtime.InteropServices
Module Module1
Function v1(given As Int16) As UInt16
Dim buffer As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(given))
Marshal.StructureToPtr(given, buffer, False)
Dim result As UInt16 = Marshal.PtrToStructure(buffer, GetType(UInt16))
v1 = result
End Function
Function v2(given As Int16) As UInt16
If given < 0 Then
given = (Not given) + 1
End If
v2 = given
End Function
Sub Main()
Dim total0 As Integer
Dim total1 As Integer
Dim t0 As DateTime = DateTime.Now()
While ((DateTime.Now() - t0).TotalSeconds() < 4)
v1(-Rnd() * Int16.MaxValue)
total0 = total0 + 1
End While
Console.WriteLine("4 seconds of v1 yielded: " & total0 & " conversions")
t0 = DateTime.Now()
While ((DateTime.Now() - t0).TotalSeconds() < 4)
v2(-Rnd() * Int16.MaxValue)
total1 = total1 + 1
End While
Console.WriteLine("4 seconds of v2 yielded: " & total1 & " conversions")
Console.ReadKey()
End Sub
End Module
奇怪的是,Marshal方法似乎与C#style cast一样有效。在我的第一次运行中,编组方法较慢,但在第二次运行时,编组方法更快。这是第二次运行的结果
4 seconds of v1 yielded: 1503403 conversions
4 seconds of v2 yielded: 1240585 conversions
4 seconds of v3 yielded: 1592731 conversions
使用此代码
using System;
using System.Runtime.InteropServices;
class Program
{
static DateTime startTime = DateTime.Now;
static double time {
get {
return (DateTime.Now - startTime).TotalMilliseconds;
}
}
static ushort v1(short given) {
if (given > 0) {
return (ushort)given;
}
return (ushort)(~given + 1);
}
static ushort v2(short given) {
var buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(given));
Marshal.StructureToPtr(given, buffer, false);
ushort result = (ushort)Marshal.PtrToStructure(buffer, typeof(ushort));
return result;
}
static ushort v3(short given)
{
return (ushort)given;
}
static void Main(string[] args)
{
int total0 = 0;
int total1 = 0;
int total2 = 0;
double t0;
t0 = time;
while (time - t0 < 4000) {
v1((short)(-new Random().NextDouble() * Int16.MaxValue));
++total0;
}
Console.WriteLine("4 seconds of v1 yielded: " + total0 + " conversions");
t0 = time;
while (time - t0 < 4000) {
v2((short)(-new Random().NextDouble() * Int16.MaxValue));
++total1;
}
Console.WriteLine("4 seconds of v2 yielded: " + total1 + " conversions");
t0 = time;
while (time - t0 < 4000) {
v3((short)(-new Random().NextDouble() * Int16.MaxValue));
++total2;
}
Console.WriteLine("4 seconds of v3 yielded: " + total2 + " conversions");
Console.ReadKey();
}
}
现在引进国王;
// ConsoleApplication3.cpp : main project file.
#include "stdafx.h"
using namespace System;
using namespace System::Runtime::InteropServices;
unsigned __int16 v4(__int16 given) {
return (unsigned __int16)given;
}
public ref class Program
{
public:
static DateTime startTime = DateTime::Now;
static property double time {
double get() {
return (DateTime::Now - startTime).TotalMilliseconds;
}
}
static UInt16 v1(Int16 given) {
if (given > 0) {
return given;
}
return (UInt16)(~given + 1);
}
static UInt16 v2(Int16 given) {
IntPtr buffer = Marshal::AllocCoTaskMem(Marshal::SizeOf(given));
Marshal::StructureToPtr(given, buffer, false);
Type ^t = UInt16::typeid;
UInt16 result = (UInt16)Marshal::PtrToStructure(buffer, t);
return result;
}
static UInt16 v3(Int16 given)
{
return (UInt16)given;
}
typedef String ^string;
static void _Main(array<string> ^args)
{
int total0 = 0;
int total1 = 0;
int total2 = 0;
int total3 = 0;
double t0;
t0 = time;
while (time - t0 < 4000) {
Double d = (gcnew Random())->NextDouble();
v1((short)(-d * Int16::MaxValue));
++total0;
}
Console::WriteLine("4 seconds of v1 yielded: " + total0 + " conversions");
t0 = time;
while (time - t0 < 4000) {
v2((short)(-((gcnew Random())->NextDouble()) * Int16::MaxValue));
++total1;
}
Console::WriteLine("4 seconds of v2 yielded: " + total1 + " conversions");
t0 = time;
while (time - t0 < 4000) {
v3((short)(-((gcnew Random())->NextDouble()) * Int16::MaxValue));
++total2;
}
Console::WriteLine("4 seconds of v3 yielded: " + total2 + " conversions");
t0 = time;
while (time - t0 < 4000) {
v4((short)(-((gcnew Random())->NextDouble()) * Int16::MaxValue));
++total3;
}
Console::WriteLine("4 seconds of v4 yielded: " + total3 + " conversions");
Console::ReadKey();
}
};
int main(array<System::String ^> ^args)
{
Program::_Main(args);
return 0;
}
嗯,结果非常有趣
4 seconds of v1 yielded: 1417901 conversions
4 seconds of v2 yielded: 967417 conversions
4 seconds of v3 yielded: 1624141 conversions
4 seconds of v4 yielded: 1627827 conversions
答案 7 :(得分:0)
Necromancing。
作为Marc Gravell答案的补充,如果你想知道如何在头脑中做到这一点:
您通常可以将其写为:
<unsigned_type> value = unchecked(<unsigned_type>.MaxValue + your_minus_value + 1);
由于类型检查,代码如下:
public uint int2uint(int a)
{
int sign = Math.Sign(a);
uint val = (uint) Math.Abs(a);
uint unsignedValue;
if(sign > 0) // +a
unsignedValue = unchecked(UInt32.MaxValue + val + 1);
else // -a, a=0
unsignedValue = unchecked(UInt32.MaxValue - val + 1);
return unsignedValue;
}
然后,如果你想在头脑中做到这一点,你可以这样做:
BigInt mentalResult= <unsigned_type>.MaxValue + your_value;
mentalResult = mentalResult % <unsigned_type>.MaxValue;
if (your_value < 0) // your_value is a minus value
mentalResult++;
// mentalResult is now the value you search
答案 8 :(得分:0)
如果您需要经常执行此操作,则可以创建如下所示的高性能扩展方法:
Imports System.Runtime.CompilerServices
Module SignConversionExtensions
<StructLayout(LayoutKind.Explicit)> _
Private Structure Union
<FieldOffset(0)> Public Int16 As Int16
<FieldOffset(0)> Public UInt16 As UInt16
End Structure
<Extension()> Public Function ToSigned(ByVal n As UInt16) As Int16
Return New Union() With {.UInt16 = n}.Int16
End Function
<Extension()> Public Function ToUnsigned(ByVal n As Int16) As UInt16
Return New Union() With {.Int16 = n}.UInt16
End Function
End Module
这使无符号转换非常简单:
Dim x As UShort = UShort.MaxValue ' unsigned x = 0xFFFF (65535)
Dim y As Short = x.ToSigned ' signed y = 0xFFFF (-1)
答案 9 :(得分:0)
在下面的示例中,马克·格雷夫(Marc Gravell)的答案得到扩展,以证明在VB中的有用性:
<System.Runtime.InteropServices.StructLayout(Runtime.InteropServices.LayoutKind.Explicit)>
Structure vbUnion16
<System.Runtime.InteropServices.FieldOffset(0)>
Public UnSigned16 As UInt16
<System.Runtime.InteropServices.FieldOffset(0)>
Public Signed16 As Int16
<System.Runtime.InteropServices.FieldOffset(0)>
Public High8 As Byte
<System.Runtime.InteropServices.FieldOffset(1)>
Public Low8 As Byte
End Structure
从概念上讲,它与“转换”变量类型不同。而是,该方法演示了存储实体。同时,提供了访问其中各个部分的不同方式。
由于该操作是“访问”而不是“转换”,因此它非常快速,精简和高效(请参阅成员对Marc的评论)。
Endianess由编译器处理。
答案 10 :(得分:-1)
不知道VB,但我希望它与C#类似,因为它是.NET代码。 在C#中,您只需使用类型转换:
UInt16 ui = 65000;
Int16 i = (Int16)ui;
完成。