将固定大小的缓冲区(字节数组)转换为字符串。

3

我在SO和其他论坛上看到了几个相关主题,但没有找到可行的答案来回答我的问题。

这是我的代码:

[StructLayout(LayoutKind.Explicit, Size = 128)]
internal unsafe struct Frame
{
    [FieldOffset(0)]
    public fixed byte Bytes[128];

    [FieldOffset(0)]
    public long Low;

    [FieldOffset(128 - sizeof(long))]
    public long High;
}

unsafe private void button32_Click(object sender, EventArgs e)
{
    Frame frame;

    // ERROR: Error 15  You cannot use the fixed statement to take the address of an already fixed expression
    fixed (byte* ptr = frame.Bytes)
    {

    }

    // ERROR
    Console.Write(System.Text.Encoding.ASCII.GetString(frame.Bytes, 0, 128));
    frame.Low = 1234;
    //Console.Write(System.Text.Encoding.ASCII.GetString(frame.Bytes));
    frame.High = 5678;
    //Console.Write(System.Text.Encoding.ASCII.GetString(frame.Bytes));
}

如果您仅使用ASCII字符集(或者也许是采用startlength重载),那么new string((sbyte*) frame.Bytes)应该可以正常工作。 - leppie
“任何值”是什么意思?使用ASCII以外的东西吗? - leppie
我指的是字节数组是二进制的。它可以包含任何值。我只想将其视为字符串以检查更改的事实(调试目的)。 - IamIC
根据文档,它实际上使用当前系统编码,所以理论上应该适用于您的目的。 - leppie
1
调试器显示属性在这里可能是一个更好的选择,我个人认为。 - leppie
显示剩余3条评论
4个回答

3

将结构体包装在另一个类中,以消除固定指针问题。这将创建新类的内存框架内的struct。然后将fixed数组转换为byte[],以消除GetString()问题。也许这有帮助?

namespace test
{
        [StructLayout(LayoutKind.Explicit, Size = 128)]
        internal unsafe struct Frame
        {
            [FieldOffset(0)]
            public fixed byte Bytes[128];

            [FieldOffset(0)]
            public long Low;

            [FieldOffset(128 - sizeof(long))]
            public long High;                
        }

    internal class NewClass
    {
        public Frame FixedBytesArray;
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            unsafe
            {
                NewClass NewType = new NewClass();
                NewType.FixedBytesArray.High = 12345;
                NewType.FixedBytesArray.Low = 6789;


                fixed (byte* ptr = NewType.FixedBytesArray.Bytes)
                {
                    byte[] bytes = new byte[128];
                    int index = 0;
                    for (byte* counter = ptr; *counter != 0; counter++)
                    {
                        bytes[index++] = *counter;
                    }

                    Console.Write(System.Text.Encoding.ASCII.GetString(bytes, 0, 128));
                }
            }    
        }
    }
}

1
你的意思是要创建一个byte[]吗?我认为这样做行不通,因为尽管数组是引用类型,但它的所有值都是值类型。每个值类型都有自己的引用。因此,数组包含对其值的引用。但我们只提供了数组的第一个地址,编译器不知道在哪里找到这些值。 - BionicCode
希望你觉得它有用。这是一种非常强大、高效的方法,可以做一些通常看起来不可能的事情,比如将浮点数转换为整数等。 - IamIC

1

以上的方法都不适用于我,因此我创建了另一个解决方案:

StringBuilder sb = new StringBuilder();
fixed (byte* b = fixedByteArray)
{
  for (int i = 0; i < knownLengthOfByteArray; i++)
  {
    sb.Append((char)b[i]);
  }
}
return sb.ToString();

适用于 ANSI 字符串。


1
static byte[] GetBytes(string str)
{
    byte[] bytes = new byte[str.Length * sizeof(char)];
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;
}

static string GetString(byte[] bytes)
{
    char[] chars = new char[bytes.Length / sizeof(char)];
    System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
    return new string(chars);
}


static byte[] StringToByteArray(string str, int length) 
{
    return Encoding.ASCII.GetBytes(str.PadRight(length, ' '));
}  

谢谢。Console.Write(GetString(frame.Bytes)); 不起作用,我认为它期望一个指针兼容的方法。 - IamIC

0
编译器错误已经很明确地指出了:你试图修复已经被修复的东西...
只有在分配指针时才需要修复引用。这可以防止引用被移动到内存中的其他位置(垃圾回收),从而使引用“固定”(使用 MS Word)。在你的情况下,你不需要在定义时修复你的结构体,而是在引用指针时通过应用“fixed”语句来修复“source”(你代码的这部分是正确的)。
解决方案应该是从你的结构体中删除修复语句。 如果你想了解更多信息,请阅读:MSDN - fixed Statement (C# Reference)

fixed语句具有微妙的优势,例如自动创建结构而无需显式地进行,这克服了其他问题,如结构的初始化。 - IamIC
为什么您要在两个不同的属性中使用相同的 fieldoffset? - BionicCode
我理解了双重固定,但不确定如何解决。字节数组被表示为长整型数组,因此出现了“重复地址”。 - IamIC
抱歉,我只是想理解一下。从我的角度来看,您没有为该字段分配引用,而是将它们显式地放置在内存中的特定位置。您在内存中为结构体保留了一个128字节的块。现在,您通过明确告诉编译器在这个内存块中创建字段的位置来显式地组织这个区域。您确定您没有覆盖您的字节数组吗? - BionicCode
数组从位置0开始。另一个字段在同一位置创建。因此,没有任何被覆盖的内容?我猜测您正在用长整型字段覆盖字节数组(其大小是固定的!),但内存区域仍然是固定的,只是位置不同了。 - BionicCode
我故意覆盖。这是一个类型转换技巧。我可以更新长整型,数组(一个128位的密钥)会自动更新。我也可以更新数组,长整型也会自动更新。很巧妙 ;) - IamIC

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