gpt4 book ai didi

C# - 编写通用方法来处理位操作

转载 作者:行者123 更新时间:2023-11-30 15:32:00 24 4
gpt4 key购买 nike

我正在开发一种工具,该工具必须符合规范,该规范将大量数据打包成跨字节边界的位。示例:2 个字节编码 2 个字段,10 位值,6 位容差。其他字段可能跨越 2-4 个字节并分成更多字段。

与其与 C# 抗争并尝试使用位域获取结构(如在 C++ 中),我认为另一种选择是在发送数据之前/接收数据之后创建通用位打包/解包函数,并使用 C# 中的所有数据标准类型:byte、short、int、long等。

我是 C# 的新手,所以我不确定处理此问题的最佳方法。根据我的阅读,使用 unsafe不鼓励使用指针,但我尝试使用泛型类型的尝试惨遭失败:

private static bool GetBitsFromByte<T,U>(T input, byte count, out U output, byte start = 0) where T:struct where U:struct
{
if (input == default(T))
return false;

if( (start + count) > Marshal.SizeOf(input))
return false;

if(count > Marshal.SizeOf(output))
return false;

// I'd like to setup the correct output container based on the
// number of bits that are needed
if(count <= 8)
output = new byte();
else if (count <= 16)
output = new UInt16();
else if (count <= 32)
output = new UInt32();
else if (count <= 64)
output = new UInt64();
else
return false;

output = 0; // Init output

// Copy bits out in order
for (int i = start; i < count; i++)
{
output |= (input & (1 << i)); // This is not possible with generic types from my understanding
}
return true;
}

我会用这样的方法调用方法,从 data_in 中提取 10 位(从 LSB)进入data_out接下来的 6 位来自 data_in进入next_data_out .

Uint32 data_in = 0xdeadbeef;
Uint16 data_out;
byte next_data_out;
if(GetBitsFromByte<Uint32,Uint16>(data_in, 10, out data_out, 0))
{
// data_out should now = 0x2EF
if(GetBitsFromByte<Uint32,byte>(data_in, 6, out next_data_out, data_out.Length))
{
// next_data_out should now = 0x2F
}
}

我宁愿不必为 byte 的所有可能组合编写函数, ushort , uint , ulong ,尽管我想这是另一种选择。

我已经看过 BitConverter类,但这是针对不操作位的字节数组。我也明白我不能做类似的事情:where T : INumericwhere T : System.ValueType ,所以我愿意接受建议。

谢谢!

最佳答案

如您所知,您不能执行 where T : INumeric,因此无论您编写什么,都可能必须有一些变体以支持不同的数字类型。

我可能会使用 BitArray并根据需要编写与其他数据类型相互转换的方法。然后,您最多需要一种方法来往于每种数字类型,而不是每种类型的组合都需要一种方法。 (C#中有8-ish integer types,所以最坏的情况是8+8=16左右,而不是8*8=64)

您可能会使用 T4 Templates为 8 位整数类型生成方法,如果您不喜欢手动复制/粘贴的想法,并在发生变化时更新它。

uint data_in = 0xdeadbeef;
ushort data_out;
byte next_data_out;
// pay attention to BitConverter.IsLittleEndian here!
// you might need to write your own conversion methods,
// or do a Reverse() or find a better library
var bits = new BitArray(BitConverter.GetBytes(data_in));
if (bits.TryConvertToUInt16(out data_out, 10))
{
Console.WriteLine(data_out.ToString("X")); // 2EF
if (bits.TryConvertToByte(out next_data_out, 6, 10))
{
Console.WriteLine(next_data_out.ToString("X")); // 2F
}
}


private static bool Validate(BitArray bits, int len, int start, int size)
{
return len < size * 8 && bits.Count > start + len;
}
public static bool TryConvertToUInt16(this BitArray bits, out ushort output, int len, int start = 0)
{
output = 0;
if (!Validate(bits, len, start, sizeof(ushort)))
return false;
for (int i = start; i < len + start; i++)
{
output |= (ushort)(bits[i] ? 1 << (i - start) : 0);
}
return true;
}
public static bool TryConvertToByte(this BitArray bits, out byte output, int len, int start = 0)
{
output = 0;
if (!Validate(bits, len, start, sizeof(byte)))
return false;
for (int i = start; i < len + start; i++)
{
output |= (byte)(bits[i] ? 1 << (i - start) : 0);
}
return true;
}

关于C# - 编写通用方法来处理位操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19777116/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com