Структура C # для байтового массива, приводящего к 19 элементам вместо 20 - PullRequest
0 голосов
/ 26 июня 2018

UDP-сервер и клиент работают и не показывают никаких ошибок при компиляции или запуске, кроме как после предоставления ему более 20 символов.Затем внезапно у меня только 19 символов возвращаются на стороне сервера.

Похоже, что SizeConst строки имеет фактическое измерение -1.

Когда я отправляю строки, это работает, пока я не получу строку длиннее 20 символов.Он хранит только 19 символов, хотя SizeConst = 20.(а когда 3, то только 2 символа и т. д.)

Может кто-нибудь объяснить, почему я вдруг пропускаю некоторые данные?

/******************** STRUCT *****************************/
[StructLayout(LayoutKind.Sequential)]
public struct TEST
{
    public string Buffer; 
    public int     number;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    public string  aString;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
    public byte[] innerTestArray;
}


/****************** CLIENT ********************************//
static void Main(string[] args)
    {
        //Start ServerSide acknowledge
        byte[] resp = Encoding.ASCII.GetBytes("INIT");
        sendData(resp);

        while (true)
        {
            TEST test = new TEST();
            Console.WriteLine("");
            Console.WriteLine("ReadLine : ");
            test.aString = Console.ReadLine();
            test.number = 10;
            test.innerTestArray = null;
            test.Buffer = null;
            byte[] arr = structToBytes(test);
            sendData(arr);
        }
    }

/**************** MARSHAL FUNCTIONS *************************/
static byte[] structToBytes(object str)
{
        byte[] arr = new byte[Marshal.SizeOf(str)];
        IntPtr pnt = Marshal.AllocHGlobal(Marshal.SizeOf(str));
        Marshal.StructureToPtr(str, pnt, false);
        Marshal.Copy(pnt, arr, 0, Marshal.SizeOf(str));
        Marshal.FreeHGlobal(pnt);
        return arr;
}

static TEST structFromBytes(byte[] arr)
{
        TEST str = new TEST();
        int size = Marshal.SizeOf(str);
        IntPtr ptr = Marshal.AllocHGlobal(size);
        Marshal.Copy(arr, 0, ptr, size);
        str = (TEST)Marshal.PtrToStructure(ptr, str.GetType());
        Marshal.FreeHGlobal(ptr);
        return str;
}


[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]

В этом примере явыделено 20 как SizeConstant для строки.Но когда я получаю строку, она имеет SizeOf(string) = 19.

Также было бы неплохо иметь более гибкий подход для строки и других массивов, чтобы обеспечить большую гибкость.То есть не использовать SizeConst в структуре.Как и в этом примере, у меня есть только некоторые небольшие данные, но позже у меня есть некоторые различия в данных для отправки.Список и массивы структур и различных типов данных.

Любые СОВЕТЫ, ТРИКИ, ИДЕИ ??

PS: ДЕМО-КОД на https://github.com/ritskes/C-UDP-struct-to-byte-DEMO-with-server-and-client

1 Ответ

0 голосов
/ 26 июня 2018

Это происходит потому, что взаимодействие предполагает, что строка будет заканчиваться нулем, следовательно, маршаллинг добавляет нулевой терминатор .Это означает, что самой длинной строкой может быть 19 символов, допускающих нулевой терминатор.

(Обратите внимание, что в документации фактически не говорится, что ByValTStr добавит нулевой терминатор - но это так!)

Следующее компилируемое консольное приложение демонстрирует проблему:

using System;
using System.Runtime.InteropServices;

namespace Demo
{
    [StructLayout(LayoutKind.Sequential)]
    public struct TEST
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
        public string aString;
    }

    class Program
    {
        static void Main()
        {
            TEST test = new TEST();

            test.aString = "1234567890123456789012345";

            int    size = Marshal.SizeOf(test);
            byte[] arr  = new byte[size];

            IntPtr ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(test, ptr, true);
            Marshal.Copy(ptr, arr, 0, size);

            Console.WriteLine("Bytes: " + string.Join(", ", arr));

            test = Marshal.PtrToStructure<TEST>(ptr);
            Marshal.FreeHGlobal(ptr);

            Console.WriteLine(test.aString); // Prints "1234567890123456789" - only 19 characters.
        }
    }
}

Решение может заключаться в использовании вместо этого массива char:

using System;
using System.Runtime.InteropServices;

namespace Demo
{
    [StructLayout(LayoutKind.Sequential)]
    public struct TEST
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        public char[] aString;
    }

    class Program
    {
        static void Main()
        {
            TEST test = new TEST();

            test.aString = "1234567890123456789012345".ToCharArray();

            int    size = Marshal.SizeOf(test);
            byte[] arr  = new byte[size];

            IntPtr ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(test, ptr, true);
            Marshal.Copy(ptr, arr, 0, size);

            Console.WriteLine("Bytes: " + string.Join(", ", arr));

            test = Marshal.PtrToStructure<TEST>(ptr);
            Marshal.FreeHGlobal(ptr);

            Console.WriteLine(new string(test.aString)); // Prints "12345678901234567890" - all 20 characters.
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...