- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我是一名经验丰富的 Python 开发人员,并且已经爱上了它的许多便利。实际上,我了解 C# 已有一段时间,但最近接触了一些更高级的编码。
我想知道是否有一种方法可以将 C# 中的字节数组“解析”为一组(不同大小的)项。
假设我们有这个:
python :
import struct
byteArray = "\xFF\xFF\x00\x00\x00\xFF\x01\x00\x00\x00"
numbers = struct.unpack("<LHL",byteArray)
print numbers[0] # 65535
print numbers[1] # 255
print numbers[2] # 1
newNumbers = [0, 255, 1023]
byteArray = struct.pack("<HHL",newNumbers)
print byteArray # '\x00\x00\xFF\x00\xFF\x03\x00\x00'
我想在 C# 中实现相同的效果,而不是像这样使用大量困惑的代码:
C#:
byte[] byteArray = new byte[] { 255, 255, 0, 0, 0, 255, 1, 0, 0, 0 };
byte[] temp;
int[] values = new int[3];
temp = new byte[4];
Array.Copy(byteArray, 0, temp, 0, 4);
values[0] = BitConverter.ToInt32(temp);
temp = new byte[2];
Array.Copy(byteArray, 4, temp, 0, 2);
values[1] = BitConverter.ToInt16(temp);
temp = new byte[4];
Array.Copy(byteArray, 8, temp, 0, 4);
values[2] = BitConverter.ToInt32(temp);
// Now values contains an array of integer values.
// It would be OK to assume a common maximum (e.g. Int64) and just cast up to that,
// but we still have to consider the size of the source bytes.
// Now the other way.
int[] values = new int[] { 0, 255, 1023 };
byteArray = new byte[8];
temp = BitConverter.GetBytes(values[0]);
Array.Copy(temp,2,byteArray,0,2);
temp = BitConverter.GetBytes(values[1]);
Array.Copy(temp,2,byteArray,2,2);
temp = BitConverter.GetBytes(values[2]);
Array.Copy(temp,0,byteArray,4,4);
很明显,我拥有的 C# 代码非常具体并且在任何方面都不是真正可重用的。
建议?
最佳答案
我最终编写了自己的类来处理这个问题。它非常复杂,但它似乎确实有效。它也不完整,但它可以满足我目前的需要。请放心使用它,如果有任何好的改进,请告诉我。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
// This is a crude implementation of a format string based struct converter for C#.
// This is probably not the best implementation, the fastest implementation, the most bug-proof implementation, or even the most functional implementation.
// It's provided as-is for free. Enjoy.
public class StructConverter
{
// We use this function to provide an easier way to type-agnostically call the GetBytes method of the BitConverter class.
// This means we can have much cleaner code below.
private static byte[] TypeAgnosticGetBytes(object o)
{
if (o is int) return BitConverter.GetBytes((int)o);
if (o is uint) return BitConverter.GetBytes((uint)o);
if (o is long) return BitConverter.GetBytes((long)o);
if (o is ulong) return BitConverter.GetBytes((ulong)o);
if (o is short) return BitConverter.GetBytes((short)o);
if (o is ushort) return BitConverter.GetBytes((ushort)o);
if (o is byte || o is sbyte) return new byte[] { (byte)o };
throw new ArgumentException("Unsupported object type found");
}
private static string GetFormatSpecifierFor(object o)
{
if (o is int) return "i";
if (o is uint) return "I";
if (o is long) return "q";
if (o is ulong) return "Q";
if (o is short) return "h";
if (o is ushort) return "H";
if (o is byte) return "B";
if (o is sbyte) return "b";
throw new ArgumentException("Unsupported object type found");
}
/// <summary>
/// Convert a byte array into an array of objects based on Python's "struct.unpack" protocol.
/// </summary>
/// <param name="fmt">A "struct.pack"-compatible format string</param>
/// <param name="bytes">An array of bytes to convert to objects</param>
/// <returns>Array of objects.</returns>
/// <remarks>You are responsible for casting the objects in the array back to their proper types.</remarks>
public static object[] Unpack(string fmt, byte[] bytes)
{
Debug.WriteLine("Format string is length {0}, {1} bytes provided.", fmt.Length, bytes.Length);
// First we parse the format string to make sure it's proper.
if (fmt.Length < 1) throw new ArgumentException("Format string cannot be empty.");
bool endianFlip = false;
if (fmt.Substring(0, 1) == "<")
{
Debug.WriteLine(" Endian marker found: little endian");
// Little endian.
// Do we need to flip endianness?
if (BitConverter.IsLittleEndian == false) endianFlip = true;
fmt = fmt.Substring(1);
}
else if (fmt.Substring(0, 1) == ">")
{
Debug.WriteLine(" Endian marker found: big endian");
// Big endian.
// Do we need to flip endianness?
if (BitConverter.IsLittleEndian == true) endianFlip = true;
fmt = fmt.Substring(1);
}
// Now, we find out how long the byte array needs to be
int totalByteLength = 0;
foreach (char c in fmt.ToCharArray())
{
Debug.WriteLine(" Format character found: {0}", c);
switch (c)
{
case 'q':
case 'Q':
totalByteLength += 8;
break;
case 'i':
case 'I':
totalByteLength += 4;
break;
case 'h':
case 'H':
totalByteLength += 2;
break;
case 'b':
case 'B':
case 'x':
totalByteLength += 1;
break;
default:
throw new ArgumentException("Invalid character found in format string.");
}
}
Debug.WriteLine("Endianness will {0}be flipped.", (object) (endianFlip == true ? "" : "NOT "));
Debug.WriteLine("The byte array is expected to be {0} bytes long.", totalByteLength);
// Test the byte array length to see if it contains as many bytes as is needed for the string.
if (bytes.Length != totalByteLength) throw new ArgumentException("The number of bytes provided does not match the total length of the format string.");
// Ok, we can go ahead and start parsing bytes!
int byteArrayPosition = 0;
List<object> outputList = new List<object>();
byte[] buf;
Debug.WriteLine("Processing byte array...");
foreach (char c in fmt.ToCharArray())
{
switch (c)
{
case 'q':
outputList.Add((object)(long)BitConverter.ToInt64(bytes,byteArrayPosition));
byteArrayPosition+=8;
Debug.WriteLine(" Added signed 64-bit integer.");
break;
case 'Q':
outputList.Add((object)(ulong)BitConverter.ToUInt64(bytes,byteArrayPosition));
byteArrayPosition+=8;
Debug.WriteLine(" Added unsigned 64-bit integer.");
break;
case 'l':
outputList.Add((object)(int)BitConverter.ToInt32(bytes, byteArrayPosition));
byteArrayPosition+=4;
Debug.WriteLine(" Added signed 32-bit integer.");
break;
case 'L':
outputList.Add((object)(uint)BitConverter.ToUInt32(bytes, byteArrayPosition));
byteArrayPosition+=4;
Debug.WriteLine(" Added unsignedsigned 32-bit integer.");
break;
case 'h':
outputList.Add((object)(short)BitConverter.ToInt16(bytes, byteArrayPosition));
byteArrayPosition += 2;
Debug.WriteLine(" Added signed 16-bit integer.");
break;
case 'H':
outputList.Add((object)(ushort)BitConverter.ToUInt16(bytes, byteArrayPosition));
byteArrayPosition += 2;
Debug.WriteLine(" Added unsigned 16-bit integer.");
break;
case 'b':
buf = new byte[1];
Array.Copy(bytes,byteArrayPosition,buf,0,1);
outputList.Add((object)(sbyte)buf[0]);
byteArrayPosition++;
Debug.WriteLine(" Added signed byte");
break;
case 'B':
buf = new byte[1];
Array.Copy(bytes, byteArrayPosition, buf, 0, 1);
outputList.Add((object)(byte)buf[0]);
byteArrayPosition++;
Debug.WriteLine(" Added unsigned byte");
break;
case 'x':
byteArrayPosition++;
Debug.WriteLine(" Ignoring a byte");
break;
default:
throw new ArgumentException("You should not be here.");
}
}
return outputList.ToArray();
}
/// <summary>
/// Convert an array of objects to a byte array, along with a string that can be used with Unpack.
/// </summary>
/// <param name="items">An object array of items to convert</param>
/// <param name="LittleEndian">Set to False if you want to use big endian output.</param>
/// <param name="NeededFormatStringToRecover">Variable to place an 'Unpack'-compatible format string into.</param>
/// <returns>A Byte array containing the objects provided in binary format.</returns>
public static byte[] Pack(object[] items, bool LittleEndian, out string NeededFormatStringToRecover)
{
// make a byte list to hold the bytes of output
List<byte> outputBytes = new List<byte>();
// should we be flipping bits for proper endinanness?
bool endianFlip = (LittleEndian != BitConverter.IsLittleEndian);
// start working on the output string
string outString = (LittleEndian == false ? ">" : "<");
// convert each item in the objects to the representative bytes
foreach (object o in items)
{
byte[] theseBytes = TypeAgnosticGetBytes(o);
if (endianFlip == true) theseBytes = (byte[])theseBytes.Reverse();
outString += GetFormatSpecifierFor(o);
outputBytes.AddRange(theseBytes);
}
NeededFormatStringToRecover = outString;
return outputBytes.ToArray();
}
public static byte[] Pack(object[] items)
{
string dummy = "";
return Pack(items, true, out dummy);
}
}
关于c# - 等效于 Python 的 C# "struct.pack/unpack"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28225303/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!