在c#中对字节数组表示的Int32求和
Posted
技术标签:
【中文标题】在c#中对字节数组表示的Int32求和【英文标题】:summing Int32 represented by byte array in c# 【发布时间】:2016-12-18 19:56:16 【问题描述】:我有一个音频数据数组,它是由字节数组表示的大量 Int32 数字(每个 4 字节元素代表一个 Int32),我想对数据进行一些操作(例如,将 10 添加到每个Int32)。
我将字节转换为 Int32,进行操作并将其转换回字节,如下例所示:
//byte[] buffer;
for (int i=0; i<buffer.Length; i+=4)
Int32 temp0 = BitConverter.ToInt32(buffer, i);
temp0 += 10;
byte[] temp1 = BitConverter.GetBytes(temp0);
for (int j=0;j<4;j++)
buffer[i + j] = temp1[j];
但我想知道是否有更好的方法来进行这种操作。
【问题讨论】:
如果你知道字节的顺序,你可以直接在字节上自己添加。 定义“更好”。你觉得这不可读吗?是不是太慢了? 我觉得这既丑陋又缓慢,任何可以改进的建议都将不胜感激。 @MillieSmith 如果这就是你的意思,它是大端,但我不确定在每次处理进位位的同时添加字节会更快。你有更好的主意吗? @pio 如果是大端,不要使用BitConverter
类。 BitConverter
类假定您系统的本机字节序。
【参考方案1】:
您可以查看.NET Reference Source 以获取有关如何从/到大端转换的指针(咧嘴笑)。
class intFromBigEndianByteArray
public byte[] b;
public int this[int i]
get
i <<= 2; // i *= 4; // optional
return (int)b[i] << 24 | (int)b[i + 1] << 16 | (int)b[i + 2] << 8 | b[i + 3];
set
i <<= 2; // i *= 4; // optional
b[i ] = (byte)(value >> 24);
b[i + 1] = (byte)(value >> 16);
b[i + 2] = (byte)(value >> 8);
b[i + 3] = (byte)value;
和样品使用:
byte[] buffer = 127, 255, 255, 255, 255, 255, 255, 255 ;//big endian int.MaxValue, -1
//bool check = BitConverter.IsLittleEndian; // true
//int test = BitConverter.ToInt32(buffer, 0); // -129 (incorrect because little endian)
var fakeIntBuffer = new intFromBigEndianByteArray() b = buffer ;
fakeIntBuffer[0] += 2; // 128, 0, 0, 1 = big endian int.MinValue - 1
fakeIntBuffer[1] += 2; // 0, 0, 0, 1 = big endian 1
Debug.Print(string.Join(", ", buffer)); // "128, 0, 0, 0, 1, 0, 0, 1"
为了获得更好的性能,您可以研究并行处理和 SIMD 指令 - Using SSE in C# 为了获得更好的性能,您可以查看Utilizing the GPU with c#
【讨论】:
谢谢!如果我想对 little endian(以 little endian 表示 int32 的字节数组)做同样的事情,我应该改变什么? >>/>24 代表 i+3 而不是 i 等等)。 @pio 只改变位移的顺序或索引的顺序就足够了,但是对于小端系统上的小端,你可以得到一个指向内存位置的 int 引用指针带有不安全代码的字节数组。 你的意思是:int [] converted = buffer; @pio 我的意思是根本不需要转换,因为字节数组将包含正确字节顺序的整数,并且只获取字节数组中的内存地址就足够了。有点像.Net 参考源fixed( byte * pbyte = &buffer[startIndex]) return *((int *) pbyte);
@pio 抱歉,这是一个糟糕的建议,因为不安全的代码和指针更适合理解它的高级用户(即使我不使用它),BitConverter.ToInt32
已经这样做了你。对于小端架构上的小端字节,我建议您使用 BinaryReader.ReadInt32
和 BinaryWriter.Write(Int32)
,您可以在 FileStream
或 MemoryStream
上使用它们【参考方案2】:
下面的方法怎么样:
struct My
public int Int;
var bytes = Enumerable.Range(0, 20).Select(n => (byte)(n + 240)).ToArray();
foreach (var b in bytes) Console.Write("0,-4", b);
// Pin the managed memory
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
for (int i = 0; i < bytes.Length; i += 4)
// Copy the data
My my = (My)Marshal.PtrToStructure<My>(handle.AddrOfPinnedObject() + i);
my.Int += 10;
// Copy back
Marshal.StructureToPtr(my, handle.AddrOfPinnedObject() + i, true);
// Unpin
handle.Free();
foreach (var b in bytes) Console.Write("0,-4", b);
我只是为了好玩。
不确定那不那么难看。
我不知道,会更快吗?测试一下。
【讨论】:
@Phil1970 - 我专门使用这些值来表明代码正确地进行了进位传播。 好吧,你没有为My
选择有意义的名称,所以当我意识到(它包含一个整数)时,我的评论已发布,但我一意识到就删除了它.
我认为在循环中包含 AddrOfPinnedObject
会产生很多开销。也许,如果你想要“安全”的代码,你必须这样做。否则,How to: Use Pointers to Copy an Array of Bytes 可能有用。以上是关于在c#中对字节数组表示的Int32求和的主要内容,如果未能解决你的问题,请参考以下文章