Fixed sbyte[] to string C#

3.1k Views Asked by At

I'm trying to get a string from memory using StrucLayout and FieldOffset

But I'm having a lot of trouble understanding how byte works.

Here is my code ATM :

[StructLayout(LayoutKind.Explicit)]
public unsafe struct InfoDetails
{
    [FieldOffset(0x14)]
    public fixed sbyte Name[50];

    public string getName
    {
        get
        {
            fixed (sbyte* namePtr = Name)
            {
                return new string(namePtr);
            }
        }
    }
}

This code returns : T. Expected result is TEZ.

Any advices on why I'm doing it wrong ? Thanks

3

There are 3 best solutions below

1
xanatos On BEST ANSWER

You could change the signature to:

[FieldOffset(0x14)]
public fixed char Name[25];

public string getName
{
    get
    {
        fixed (char* namePtr = Name)
        {
            return new string(namePtr);
        }
    }
}

Note how I changed sbyte to char and I halved the size of the buffer (because sizeof(char) == 2)

Or you could even, more simply add a single cast to char*:

fixed (sbyte* namePtr = Name)
{
    return new string((char*)namePtr);
}

without changing anything else.

3
Konamiman On

You seem to have a problem with string encoding. Consider the following test code:

unsafe
{
    InfoDetails d;
    var encoding = Encoding.Unicode;
    var stringBytes = encoding.GetBytes("TEZ");
    for(int i=0; i<stringBytes.Length; i++) d.Name[i] = (sbyte)stringBytes[i];
    Console.WriteLine(d.getName);
}

You will get indeed "T", but if you change the encoding to Encoding.ASCII you get "TEZ" as expected.

Solution: you need to know the encoding of the information beforehand, and generate the string accordingly. Looks like it's Unicode, so try this first:

fixed (sbyte* namePtr = Name)
{
  return new string(namePtr, 0, 50, Encoding.Unicode);
}
2
Cesar On

Thanks everybody for your answer, they helped me to get a working solution. I don't really know if it's the best one :

[StructLayout(LayoutKind.Explicit)]
    public unsafe struct InfoDetails
    {
        [FieldOffset(0x14)]
        public fixed byte Name[50];

        public string test
        {
            get
            {
                List<byte> clearBytes = new List<byte>();
                fixed (byte* namePtr = Name)
                {
                    for (int i = 0; i < 50; i++)
                    {
                        if (namePtr[i] == 0x0 && namePtr[i + 1] == 0x0)
                        {
                            break;
                        }
                        clearBytes.Add(namePtr[i]);
                    }
                    if (clearBytes.Count() % 2 != 0)
                    {
                        clearBytes.Add(0x00);
                    }
                    return Encoding.Unicode.GetString(clearBytes.ToArray());
                }
            }
        }

    }

Thanks a lot !