将byte[]转换为sbyte[]

14

我试图将一个byte[]数组转换成sbyte[]数组。

这是我的样例数组:

byte[] unsigned = { 0x00, 0xFF, 0x1F, 0x8F, 0x80 };

我已经尝试过这个了:

sbyte[] signed = (sbyte[])((Array)unsigned);

但这不起作用。此操作后,数组中没有任何值。

有人有更好的想法吗?


2
这段代码的意思是它可以编译并且没有错误。它会生成一个数组,几乎在任何情况下都可以用作sbyte[],但运行时仍然标记为byte[]。不确定你所说的“数组中没有值”的意思,对我来说,数组是{0,-1,31,-113,-128},与预期相符。 - CodesInChaos
编译后,签名数组中没有任何值。Visual Studio 在签名数组的每个元素中显示“?”。 - REMberry
好的,我尝试从已签名的数组中获取一个元素,它仍然有效。感谢您的帮助。我尝试使用这个解决方案。 - REMberry
那么这是一个VS的限制。VS可能无法理解具有静态类型sbyte []但动态类型byte []的数组是有效的。CLR允许此转换,但C#不允许。这是一种hack,因此在大多数应用程序中,您将想使用@Selman的建议。 - CodesInChaos
@Selmann22 不需要删除整个答案。第二部分是正确的,但我更喜欢sbyte[] signed = Array.ConvertAll(unsigned, x => unchecked((sbyte)x)); 这样即使启用了带符号算术也能正常工作。 - CodesInChaos
显示剩余3条评论
4个回答

30
sbyte[] signed = (sbyte[]) (Array) unsigned;

这是因为byte和sbyte在内存中的长度相同,不需要改变内存表示就可以进行转换。

然而,这种方法可能会导致调试器出现一些奇怪的错误。如果你的字节数组不是很大,你可以使用Array.ConvertAll代替。

sbyte[] signed = Array.ConvertAll(unsigned, b => unchecked((sbyte)b));

我会使用 unchecked((sbyte)b),这样即使启用了 checked 算术,它也能正常工作。它还可以作为文档,表明溢出是有意的,而不仅仅是性能优化。 - CodesInChaos
我的记忆告诉我,溢出检查不适用于字节/有符号字节。我可能错了。编辑:现在已经修复 :) - Simon Farshid
将255强制转换为sbyte时,使用checked算术肯定会抛出异常。可能让你感到困惑的是(byte)255 + (byte)255不会抛出异常,因为操作数被提升为int,在这里不会溢出。 - CodesInChaos
可能我已经修复了它。无论如何,感谢您指出这个问题 :) - Simon Farshid

5

使用Buffer.BlockCopy如何?这个方法的好处是可以避免逐字节进行转换检查,但缺点也是避免了逐字节进行转换检查。

var unsigned = new byte[] { 0x00, 0xFF, 0x1F, 0x8F, 0x80 };
var signed = new sbyte[unsigned.Length];
Buffer.BlockCopy(unsigned, 0, signed, 0, unsigned.Length);

这只是复制字节,值超过byte.MaxValue的将具有负数sbyte值。

只需两行代码就可以完成,速度应该很快。


不需要使用@符号。在C#中,signed/unsigned不是关键字。 - CodesInChaos
@CodesInChaos 带我走上了错误的道路。 - Jodrell

1
轻松做到像这样:

sbyte[] signed = unsigned.Select(b=>(sbyte)b).ToArray();

我不确定语法是否正确,请检查并验证。


1
这个可以工作。但是1)ConvertAll更快,而且同样易读;2)我更喜欢unchecked((sbyte)b)。请参见@Sepehr的答案以获取详细信息。 - CodesInChaos

1

旧的 .net Framework 和旧的 .net Core 不支持 reinterpret_cast,但支持 * 指针和不安全代码。 新版 .net 加入了 System.Memory 库,可以解决这个问题并复制内存。

   byte[] unsigned = { 0x00, 0xFF, 0x1F, 0x8F, 0x80 };  
   ReadOnlySpan<byte> bytesBuffer = unsigned;
   ReadOnlySpan<sbyte> sbytesBuffer = MemoryMarshal.Cast<byte, sbyte>(bytesBuffer);
   sbyte[] signed = sbytesBuffer.ToArray();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接