Начинаю учить C# :(
От: 777777w  
Дата: 11.07.16 05:14
Оценка: :)
И никак не найду гибкость, которая была у C/C++. Или ее там нет?

Принимаю из сокета пакет двоичных данных имеющих такую структуру:
struct CDataPacket
    {
    char        DevType;        // тип устройства
    BYTE        InfType;        // тип информации
    BYTE        Length;            // длина
    BYTE        Data[255];        // данные
    };

Сразу же сталкиваюсь с тем, что в C# повторить ее нельзя: здесь массивы всегда ссылочного типа. Покопавшись, все-таки нахожу что массив можно сделать fixed. Правда, из-за него одного весь проект приходится делать unsafe.

Но главная проблема дальше. Данные принимаются в массив байт. В Си я создавал указатель типа CDataPacket, указывал им на начало массива и работал с ним. Здесь указателей нет, данные ссылочного типа создаются сразу со "своими" данными, а как быть если данные уже существуют отдельно? Ведь ситуация очень распространенная, двоичные файлы тоже читаются в массив байт, как их интерпретировать как структуры неких дынных? Дальше при обработке этой структуры тоже придется преобразовывать типы — поле Data в зависимости от типа устройства и типа информации интерпретируется как другие структуры, как здесь быть?
Re: Начинаю учить C# :(
От: IncremenTop  
Дата: 11.07.16 05:21
Оценка:
Здравствуйте, 777777w, Вы писали:

7>Сразу же сталкиваюсь с тем, что в C# повторить ее нельзя: здесь массивы всегда ссылочного типа. Покопавшись, все-таки нахожу что массив можно сделать fixed. Правда, из-за него одного весь проект приходится делать unsafe.


Почему не воспользоваться Intptr?

7> Ведь ситуация очень распространенная, двоичные файлы тоже читаются в массив байт, как их интерпретировать как структуры неких дынных?


Т.е. про десериализацию вы не слышали?
Re[2]: Начинаю учить C# :(
От: 777777w  
Дата: 11.07.16 05:40
Оценка:
Здравствуйте, IncremenTop, Вы писали:

7>>Сразу же сталкиваюсь с тем, что в C# повторить ее нельзя: здесь массивы всегда ссылочного типа. Покопавшись, все-таки нахожу что массив можно сделать fixed. Правда, из-за него одного весь проект приходится делать unsafe.


IT>Почему не воспользоваться Intptr?


A platform-specific type that is used to represent a pointer or a handle.


А чем он здесь поможет?

7>> Ведь ситуация очень распространенная, двоичные файлы тоже читаются в массив байт, как их интерпретировать как структуры неких дынных?


IT>Т.е. про десериализацию вы не слышали?


Только в MFC
А где об это можно почитать? У Рихтера это слово встречается, но так, будто читатель его уже знает.
Re: Начинаю учить C# :(
От: Regular_Man  
Дата: 11.07.16 06:08
Оценка:
Здравствуйте, 777777w, Вы писали:

7>И никак не найду гибкость, которая была у C/C++. Или ее там нет?


7> ...


7>Но главная проблема дальше. Данные принимаются в массив байт. В Си я создавал указатель типа CDataPacket, указывал им на начало массива и работал с ним. Здесь указателей нет, данные ссылочного типа создаются сразу со "своими" данными, а как быть если данные уже существуют отдельно? Ведь ситуация очень распространенная, двоичные файлы тоже читаются в массив байт, как их интерпретировать как структуры неких дынных? Дальше при обработке этой структуры тоже придется преобразовывать типы — поле Data в зависимости от типа устройства и типа информации интерпретируется как другие структуры, как здесь быть?


На самом деле все есть. Вот здесь, например, можно подробно почитать https://habrahabr.ru/post/114953/
Re: Начинаю учить C# :(
От: Sinatr Германия  
Дата: 11.07.16 08:29
Оценка: +2 -1
Здравствуйте, 777777w, Вы писали:

7>Принимаю из сокета пакет двоичных данных


Вам нужно почитать главу про маршалинг. C# — управляемый язык (читай "не даст выстрелить в ногу"). Можно конечно использовать fixed, но лучше не надо.

7>данные ссылочного типа создаются сразу со "своими" данными, а как быть если данные уже существуют отдельно?


См. сериализация. Это процес превращения экземпляра обьекта в нечто другое (xml, json, etc.) и наоборот (десериализация).

7>двоичные файлы тоже читаются в массив байт, как их интерпретировать как структуры неких дынных?


Обьявите эти структуры правильно, напишите вот такой метод:

public static T ByteToStructure<T>(byte[] data)
{
    GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
    T obj = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
    handle.Free();
    return obj;
}

> Дальше при обработке этой структуры тоже придется преобразовывать типы — поле Data в зависимости от типа устройства и типа информации интерпретируется как другие структуры, как здесь быть?

Все произойдет автоматически, если правильно обьявить структуры, см. StructLayoutAttribute, FieldOffsetAttribute, MarshalAsAttribute, etc.
---
ПроГLамеры объединяйтесь..
Re: Начинаю учить C# :(
От: hardcase Пират http://nemerle.org
Дата: 11.07.16 09:29
Оценка: +1
Здравствуйте, 777777w, Вы писали:

7>Но главная проблема дальше. Данные принимаются в массив байт. В Си я создавал указатель типа CDataPacket, указывал им на начало массива и работал с ним. Здесь указателей нет, данные ссылочного типа создаются сразу со "своими" данными, а как быть если данные уже существуют отдельно? Ведь ситуация очень распространенная, двоичные файлы тоже читаются в массив байт, как их интерпретировать как структуры неких дынных? Дальше при обработке этой структуры тоже придется преобразовывать типы — поле Data в зависимости от типа устройства и типа информации интерпретируется как другие структуры, как здесь быть?


Указатели есть, у них, внезапно, даже синтаксис такой же как в C/C++, но разметить код unsafe-ами таки придется.
Реинтерпретация внутренностей структуры (аналог union) также есть, но она тонкая ручная с помощью см. StructLayoutAttribute и FieldOffsetAttribute.
/* иЗвиНите зА неРовнЫй поЧерК */
Re: Начинаю учить C# :(
От: Vladek Россия Github
Дата: 13.07.16 11:11
Оценка: -2
Здравствуйте, 777777w, Вы писали:

7>И никак не найду гибкость, которая была у C/C++. Или ее там нет?


C# язык более высокого уровня, у него своя атмосфера свои абстракции.

7>Принимаю из сокета пакет двоичных данных имеющих такую структуру:

7>Сразу же сталкиваюсь с тем, что в C# повторить ее нельзя: здесь массивы всегда ссылочного типа. Покопавшись, все-таки нахожу что массив можно сделать fixed. Правда, из-за него одного весь проект приходится делать unsafe.

Э, а этот сокет может вернуть поток данных (Stream)? Открываешь поток, читаешь из него байты и парсишь их в соответствии со своей структурой. Может быть, в .NET есть уже код для этого — какое-нибудь быстрое наложение структуры на массив байт — гуглишь, экспериментируешь.

7>Но главная проблема дальше. Данные принимаются в массив байт. В Си я создавал указатель типа CDataPacket, указывал им на начало массива и работал с ним. Здесь указателей нет, данные ссылочного типа создаются сразу со "своими" данными, а как быть если данные уже существуют отдельно? Ведь ситуация очень распространенная, двоичные файлы тоже читаются в массив байт, как их интерпретировать как структуры неких дынных? Дальше при обработке этой структуры тоже придется преобразовывать типы — поле Data в зависимости от типа устройства и типа информации интерпретируется как другие структуры, как здесь быть?


Копировать. Прочитал массив байт, быстро проанализировал его тип (проверил magic numbers), создал структуру нужного типа — заполнил её данными из массива. Управлению памятью здесь — не твоя забота, оставь это сборщику мусора. Твоя задача писать простой и понятный код, а не накладывать универсальные структуры на произвольные участки памяти.
Отредактировано 13.07.2016 11:12 Vladek . Предыдущая версия .
Re[2]: Начинаю учить C# :(
От: Философ Ад http://vk.com/id10256428
Дата: 21.07.16 19:10
Оценка: -1 :)
Здравствуйте, Regular_Man, Вы писали:

R_M>На самом деле все есть. Вот здесь, например, можно подробно почитать https://habrahabr.ru/post/114953/


Чувак там скромно умалчивает о том, что структуры в шарпе нельзя выделить в куче, и все эти fixed arrays лягут на стэке. Да и есть в шарпе, например нет struct union — именно они наибольшую головную боль вызывают. Я каждый раз, когда сталкиваюсь с Interop'ом задумываюсь о том, чтобы его писать на C++ CLI. Из-за вот такого, и из-за списков строк.
Всё сказанное выше — личное мнение, если не указано обратное.
Re: Начинаю учить C# :(
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 23.07.16 13:39
Оценка: +2
Здравствуйте, 777777w, Вы писали:

7>И никак не найду гибкость, которая была у C/C++. Или ее там нет?


7>Принимаю из сокета пакет двоичных данных имеющих такую структуру:

7>
7>struct CDataPacket
7>    {
7>    char        DevType;        // тип устройства
7>    BYTE        InfType;        // тип информации
7>    BYTE        Length;            // длина
7>    BYTE        Data[255];        // данные
7>    };
7>

7>Сразу же сталкиваюсь с тем, что в C# повторить ее нельзя: здесь массивы всегда ссылочного типа. Покопавшись, все-таки нахожу что массив можно сделать fixed. Правда, из-за него одного весь проект приходится делать unsafe.
Начни с того, что ты хочешь сделать, а потом уже думай структуры.


7>Но главная проблема дальше. Данные принимаются в массив байт. В Си я создавал указатель типа CDataPacket, указывал им на начало массива и работал с ним. Здесь указателей нет, данные ссылочного типа создаются сразу со "своими" данными, а как быть если данные уже существуют отдельно? Ведь ситуация очень распространенная, двоичные файлы тоже читаются в массив байт, как их интерпретировать как структуры неких дынных? Дальше при обработке этой структуры тоже придется преобразовывать типы — поле Data в зависимости от типа устройства и типа информации интерпретируется как другие структуры, как здесь быть?

Ты можешь привести пример кода, иллюстрирующего проблему?
В C# указатели есть и можно делать ровно то же, что и на голом C. Естественно это все unsafe.

[StructLayout(LayoutKind.Explicit)] //чтобы руками задать layout
struct DataPacket
{
    [FieldOffset(0)]
    public byte            DevType;     // тип устройства

    [FieldOffset(1)]
    public byte            InfType;     // тип информации

    [FieldOffset(2)]
    public byte            Length;      // длина

    [FieldOffset(3)]
    public fixed byte[255] Data;        // данные
};


byte[] ReadPacket() { /*some code */}


var buf = ReadPacket();

fixed( byte* p = buf ) 
{
   var s = (DataPacket*)p;
   if(s->InfType == 0x01) 
   {
      var s1 = (SomeOtherStruct*)&s->Data[0];
      //...
   }
   //...
}


Так вполне можно писать.

Но лучше сразу при парсинге получать нужные структуры.
Вряд ли тебе будут данные приходить целыми пакетами по 258 байт. Скорее тебе надо прочитать Length и потом читать ровно только байт, сколько Length. В этот момент у тебя еще не будет массива, чтобы привести его к структуре, но ты уже распарсишь нужные значения. Поэтому твой код чтения может сразу выплюнуть не массив байт, а структуру нужного типа.
Re[3]: Начинаю учить C# :(
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 23.07.16 13:47
Оценка: +2
Здравствуйте, Философ, Вы писали:

Ф>Здравствуйте, Regular_Man, Вы писали:


R_M>>На самом деле все есть. Вот здесь, например, можно подробно почитать https://habrahabr.ru/post/114953/


Ф>Чувак там скромно умалчивает о том, что структуры в шарпе нельзя выделить в куче, и все эти fixed arrays лягут на стэке.

С чего ты взял?
Marshal.AllocHGlobal

Ф>Да и есть в шарпе, например нет struct union — именно они наибольшую головную боль вызывают.

С чего ты взял? Есть StructLayout(LayoutKind.Explicit) и [FieldOffset(x)]


Ф>Я каждый раз, когда сталкиваюсь с Interop'ом задумываюсь о том, чтобы его писать на C++ CLI.

Интероп действительно проще на C++ делать, но это сразу дофига проблем дает — несколько языков в проекте, ограничения на платформы и много подобной "радости".
Если интеропа мало, то лучше один раз написать обертки на C# и как можно быстрее уйти от ковыряния с байтами и указателями.
Если весь проект это большой интероп, то лучше на C++ CLI, он для такого и был сделан.


Ф>Из-за вот такого, и из-за списков строк.

Какого еще списка строк?
Re: Начинаю учить C# :(
От: LWhisper  
Дата: 27.07.16 11:04
Оценка:
Здравствуйте, 777777w, Вы писали:

7>Но главная проблема дальше. Данные принимаются в массив байт. В Си я создавал указатель типа CDataPacket, указывал им на начало массива и работал с ним. Здесь указателей нет, данные ссылочного типа создаются сразу со "своими" данными, а как быть если данные уже существуют отдельно? Ведь ситуация очень распространенная, двоичные файлы тоже читаются в массив байт, как их интерпретировать как структуры неких дынных? Дальше при обработке этой структуры тоже придется преобразовывать типы — поле Data в зависимости от типа устройства и типа информации интерпретируется как другие структуры, как здесь быть?


Закрепляешь управляемый массив в памяти, берёшь указатель на него (предварительно проверив, что длина массива больше 0), приводишь его к нужному тебе типу и работаешь с ним точно также, как в С++.

unsafe struct CDataPacket
{
    public char DevType; // тип устройства
    public byte InfType; // тип информации
    public byte Length; // длина
    public fixed byte Data [255]; // данные
};

unsafe static void ProcessPacket(byte[] packet)
{
    if(packet == null || packet.Length == 0)
        throw new ArgumentException("packet");

    fixed(byte* ptr = packet)
    {
        CDataPacket* sPtr = (CDataPacket*)ptr;
        String data = new String((sbyte*)sPtr->Data, 0, sPtr->Length);
        Console.WriteLine(data);
    }
}
Отредактировано 27.07.2016 11:05 LWhisper . Предыдущая версия .
Re: Начинаю учить C# :(
От: DreamMaker  
Дата: 28.07.16 16:34
Оценка:
Здравствуйте, 777777w, Вы писали:

7>И никак не найду гибкость, которая была у C/C++. Или ее там нет?


в этом мире байтодрочество не приветствуется
сам сначала подобные чувства испытывал, пока не понял что на самом деле так куда как правильнее.
In P=NP we trust.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.