#pragma pack(push,1) - как сделать в С#?
От: vog Россия [реклама удалена модератором]
Дата: 15.10.08 22:19
Оценка:
Здравствуйте!

Есть С++ структура

#pragma pack(push,1)  // this pragma set alignment of elements in structure to 1 byte
struct RateInfo
{
   unsigned int      ctm;
   double            open;
   double            low;
   double            high;
   double            close;
   double            vol;
};
#pragma pack(pop)     // this pragma set alignment by default


Как бы мне эти алигменты указать в C#? Массив таких структур записан в файле, я хочу использовать
FileMapping и читать, как массив структур, наверное, без указания алигмента не обойтись?
[реклама удалена модератором]
Re: #pragma pack(push,1) - как сделать в С#?
От: samius Япония http://sams-tricks.blogspot.com
Дата: 15.10.08 22:27
Оценка: 5 (1) +1
Здравствуйте, vog, Вы писали:

vog>Здравствуйте!


vog>Есть С++ структура


vog>Как бы мне эти алигменты указать в C#? Массив таких структур записан в файле, я хочу использовать

vog>FileMapping и читать, как массив структур, наверное, без указания алигмента не обойтись?
[StructLayout(LayoutKind.Sequential)]
Re[2]: #pragma pack(push,1) - как сделать в С#?
От: vog Россия [реклама удалена модератором]
Дата: 16.10.08 08:16
Оценка:
Здравствуйте, samius, Вы писали:

S>[StructLayout(LayoutKind.Sequential)]


Спасибо, сходу не нашел
[реклама удалена модератором]
Re[2]: как перевести массив в структуре?
От: vog Россия [реклама удалена модератором]
Дата: 16.10.08 09:31
Оценка:
А как такое перевести на C#, можете подсказать? В С++ time_t имеет тип __int64, значит задаю Int64, а как быть с массивами чаров?


struct S
{
  char              copyright[64];  
  time_t            timesign;       
  char              other[11]; 
};
[реклама удалена модератором]
fixed
От: Блудов Павел Россия  
Дата: 16.10.08 09:47
Оценка: +1
Здравствуйте, vog, Вы писали:

vog>А как такое перевести на C#, можете подсказать? В С++ time_t имеет тип __int64, значит задаю Int64, а как быть с массивами чаров?

http://msdn.microsoft.com/en-us/library/zycewsya(VS.80).aspx
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re: #pragma pack(push,1) - как сделать в С#?
От: vdimas Россия  
Дата: 04.11.08 05:19
Оценка:
Здравствуйте, vog, Вы писали:

vog>Как бы мне эти алигменты указать в C#? Массив таких структур записан в файле, я хочу использовать

vog>FileMapping и читать, как массив структур, наверное, без указания алигмента не обойтись?

А смысл делать FileMapping, если тебе для прочтения любого поля будет маршаллиться т.е. долго и нудно копироваться вся структура, да еще и через рефлексию? Автоматический маршаллинг убъет нафик любой выигрыш от FileMapping.

Сделай обертку типа такого:
unsafe struct RateInfo
{
    private byte* _addr;
    
    public RateInfo(IntPtr addr) {
        _addr = addr.ToPointer();
    }
    
    uint Ctm { get { return *(uint*)_addr; } }
    double Open { get { return *(double*)(_addr+4); } }
    double Low { get { return *(double*)(_addr+12); } }
    ...
}


Структура хранит адрес элемента, с которым работаешь, а в св-вах ручками пишем код, который нам нарисовал бы какой-нить C++/CLI-компилятор при обращении к полям твоей исходной структуры, т.е. будет работать с нативной скоростью без проседания быстродействия в сотню раз на маршаллинге.

Идеально было бы сделать это всё не ручками, а создать вспомогательную либу именно в упомянутом C++/CLI, дабы сохранить принцип реализации, но убрать нелицеприятный хардкод.

Принцип там будет примерно такой:
#pragma unmanaged
#pragma (push, пиф, паф и что угодно из С++)

struct NativeRateInfo {
    unsigned ctm;
    ...
};

#pragma managed

public value class RateInfo {
    NativeRateInfo* ptr;
    
public:
    RateInfo(NativeRateInfo* p) : ptr(p) {}

    // :)
    void Next() { ptr++; } 
    
    unsigned Ctm { unsigned get() { return ptr.ctm; } }
    ...
};
... << RSDN@Home 1.2.0 alpha rev. 786>>
Re[2]: #pragma pack(push,1) - как сделать в С#?
От: Spirit_1 Россия  
Дата: 05.12.08 05:43
Оценка:
Здравствуйте, vdimas, Вы писали:

V>А смысл делать FileMapping, если тебе для прочтения любого поля будет маршаллиться т.е. долго и нудно копироваться вся структура, да еще и через рефлексию? Автоматический маршаллинг убъет нафик любой выигрыш от FileMapping.


Придумал такой вариант без маршаллинга, но в unsafe:

        [StructLayout(LayoutKind.Sequential, Pack = 1)] // Pack=1 тоже жизненно необходимо, по умолчанию выравнивается вроде по 4 байта или определяется платформой

        unsafe struct RateInfo
        {
            uint ctm;
            double open;
            double low;
            double high;
            double close;
            double vol;
            public fixed char copyright[64]; // ну или как там у вас...
        }

//... а в соответствующей процедуре так:
                byte[] buf = new byte[sizeof(RateInfo)];
                GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned);
                FileStream fs = new FileStream("infile");
                fs.Read(buf, 0, buf.Length);                           // ну или как то иначе заполняем
                RateInfo* ptr = (RateInfo*)handle.AddrOfPinnedObject().ToPointer();
//дальше поля структуры доступны через операцию ->

// а когда все закрывается и уничтожается не забыть освободить указатель
                handle.Free();


Ну естественно, все это лучше обернуть в аккуратно написанный класс И никакого маршаллинга и лишнего копирования, а тем более процедур отражения.
Re[3]: #pragma pack(push,1) - как сделать в С#?
От: TK Лес кывт.рф
Дата: 05.12.08 08:24
Оценка:
Здравствуйте, Spirit_1, Вы писали:

S_>//... а в соответствующей процедуре так:

S_> byte[] buf = new byte[sizeof(RateInfo)];
S_> GCHandle handle = GCHandle.Alloc(buf, GCHandleType.Pinned);
S_> FileStream fs = new FileStream("infile");
S_> fs.Read(buf, 0, buf.Length); // ну или как то иначе заполняем
S_> RateInfo* ptr = (RateInfo*)handle.AddrOfPinnedObject().ToPointer();
S_>//дальше поля структуры доступны через операцию ->

Непонятен только смысл приседаний с GCHandle — намного проще сразу получить fixed указатель на первый элемент и уже потом закастить его к RateInfo*
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[4]: #pragma pack(push,1) - как сделать в С#?
От: Spirit_1 Россия  
Дата: 05.12.08 08:40
Оценка:
Здравствуйте, TK, Вы писали:

TK>Непонятен только смысл приседаний с GCHandle — намного проще сразу получить fixed указатель на первый элемент и уже потом закастить его к RateInfo*


Ну как бы двух зайцев убиваем. Во-первых, первый элемент структуры может поменяться в процессе кодинга и надо будет вспоминать, где ты там делал этот fixed *, или вообще быть неизвестным, если писать шаблон. Ну и конечно как и с fixed защита от перемещения GC, только с большим временем, если переменные нелокальные. Тогда логично операции выделения буфера и приведения указателя поместить в конструктор, сделать буфер и указатель приватными полями и забыть про GC до самого Dispose.
Re[5]: #pragma pack(push,1) - как сделать в С#?
От: samius Япония http://sams-tricks.blogspot.com
Дата: 05.12.08 08:42
Оценка:
Здравствуйте, Spirit_1, Вы писали:

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


TK>>Непонятен только смысл приседаний с GCHandle — намного проще сразу получить fixed указатель на первый элемент и уже потом закастить его к RateInfo*


S_>Ну как бы двух зайцев убиваем. Во-первых, первый элемент структуры может поменяться в процессе кодинга и надо будет вспоминать, где ты там делал этот fixed *, или вообще быть неизвестным, если писать шаблон.

С шаблоном этот номер не пройдет!
Re[6]: #pragma pack(push,1) - как сделать в С#?
От: Spirit_1 Россия  
Дата: 05.12.08 08:47
Оценка:
Здравствуйте, samius, Вы писали:

S_>>Ну как бы двух зайцев убиваем. Во-первых, первый элемент структуры может поменяться в процессе кодинга и надо будет вспоминать, где ты там делал этот fixed *, или вообще быть неизвестным, если писать шаблон.

S>С шаблоном этот номер не пройдет!

Да? Извините, видимо не шарю. А жаль, хотел написать. А то сильно скучаю по сишному fread
Re[5]: #pragma pack(push,1) - как сделать в С#?
От: TK Лес кывт.рф
Дата: 05.12.08 08:53
Оценка:
Здравствуйте, Spirit_1, Вы писали:

S_>Ну как бы двух зайцев убиваем. Во-первых, первый элемент структуры может поменяться в процессе кодинга и надо будет вспоминать, где ты там делал этот fixed *, или вообще быть неизвестным, если писать шаблон.


Я пока вижу только то, что в случае исключения GCHandle.Free вызван не будет. С AddrOfPinnedObject проблема аналогичная — если структура поменялась то, придется вспоминать где она могла использоваться.

S_>Ну и конечно как и с fixed защита от перемещения GC, только с большим временем, если переменные нелокальные.


Что есть "нелокальные переменные"
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[7]: #pragma pack(push,1) - как сделать в С#?
От: samius Япония http://sams-tricks.blogspot.com
Дата: 05.12.08 08:54
Оценка:
Здравствуйте, Spirit_1, Вы писали:

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


S_>>>Ну как бы двух зайцев убиваем. Во-первых, первый элемент структуры может поменяться в процессе кодинга и надо будет вспоминать, где ты там делал этот fixed *, или вообще быть неизвестным, если писать шаблон.

S>>С шаблоном этот номер не пройдет!

S_>Да? Извините, видимо не шарю. А жаль, хотел написать. А то сильно скучаю по сишному fread


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

Вообще, если бы было специальное ограничение на тип шаблона:
where T: unmanaged

То можно было бы и шаблонный метод сделать.
Но такое требуется довольно редко, большой необходимости в этом нет.
Re[6]: #pragma pack(push,1) - как сделать в С#?
От: Spirit_1 Россия  
Дата: 05.12.08 10:08
Оценка:
Здравствуйте, TK, Вы писали:

TK>Я пока вижу только то, что в случае исключения GCHandle.Free вызван не будет. С AddrOfPinnedObject проблема аналогичная — если структура поменялась то, придется вспоминать где она могла использоваться.

Насчет исключений согласен. Если это критично, такой вариант не пойдет. А если например создание буфера и приведение к нему указателя находятся в одном методе, а обращения к полям через указатель в другом, то о каком fixed может быть речь?

TK>Что есть "нелокальные переменные"

Я имел в виду примерно такую реализацию "обертки"

        unsafe struct RateInfo // наша структура
        {
   
            public double open;
//...
        }

        unsafe class StructReader
        {
            byte[] buf; // вот это я назвал "нелокальными переменными"
            RateInfo* ptr;
            GCHandle handle;
            FileStream fs;

            public StructReader()
            {
                byte[] buf = new byte[sizeof(RateInfo)];
                handle = GCHandle.Alloc(buf, GCHandleType.Pinned);
                //ptr = (RateInfo*)buf;  // так  пишет Cannot convert ...
                ptr = (RateInfo*)handle.AddrOfPinnedObject().ToPointer();
            }
            public void OpenDataFile(string filename)
            {
                fs = new FileStream(filename,FileMode.Open);
            }
            public void ReadNext()
            {
                fs.Read(buf, 0, buf.Length);
            }

            // Обертка структуры
            public double open
            {
                get { return ptr->open; }
                set { ptr->open = value; }
            }
            // etc...

            public void CloseDataFile()
            {
                fs.Close();
                handle.Free();
            }
        }

Конечно, можно в каждом аксессоре ставить fixed и приводить указатели, но как то это не очень...
Re[8]: #pragma pack(push,1) - как сделать в С#?
От: Spirit_1 Россия  
Дата: 05.12.08 10:24
Оценка:
Здравствуйте, samius, Вы писали:

S>Вообще, если бы было специальное ограничение на тип шаблона:

S>
S>where T: unmanaged
S>

S>То можно было бы и шаблонный метод сделать.
Это, наверное, противоречит принципу работы шаблонов в C#.

S>Но такое требуется довольно редко, большой необходимости в этом нет.

Да вот к сожалению не все файлы пока записываются в формате XML или сериализацией объектов. Просто имею дело с форматами записи сейсмических данных, которые увы не мной придуманы и которых надо придерживаться как общепринятых отраслевых стандартов. В C++ их чтение никаких затруднений не вызывает, а в C# эта казалось бы простая операция превратилась в танцы с бубном.
Re[9]: #pragma pack(push,1) - как сделать в С#?
От: samius Япония http://sams-tricks.blogspot.com
Дата: 05.12.08 10:46
Оценка: 1 (1)
Здравствуйте, Spirit_1, Вы писали:

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


S>>Вообще, если бы было специальное ограничение на тип шаблона:

S>>
S>>where T: unmanaged
S>>

S>>То можно было бы и шаблонный метод сделать.
S_>Это, наверное, противоречит принципу работы шаблонов в C#.
Если бы компилятор умел отслеживать, что в структуре нет managed полей, то это ничему бы не противоречило.

S>>Но такое требуется довольно редко, большой необходимости в этом нет.

S_>Да вот к сожалению не все файлы пока записываются в формате XML или сериализацией объектов. Просто имею дело с форматами записи сейсмических данных, которые увы не мной придуманы и которых надо придерживаться как общепринятых отраслевых стандартов. В C++ их чтение никаких затруднений не вызывает, а в C# эта казалось бы простая операция превратилась в танцы с бубном.
Если таких структур больше, чем хотелось бы писать методов конвертации для каждой, то можно воспользоваться Emit-ом и нагенерить сериализаторов, прикрутить их к generic классу, в конце концов.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.