2017-01-26 6 views
1

Я имею следующую структуру (пример) в C:Как перевести C-структуру на управляемом C# эквивалент

typedef struct 
{ 
    int64  data_size; 
    uint32  avgdelay; 
    int   esize;  
    void  *epayload; 
} stats_t; 

Управляемая C# эквивалент следующим образом:

[StructLayout(LayoutKind.Sequential, Size = 4)] 
public struct stats_t 
{ 
    public Int64 datasize; 

    public UInt32 avgdelay; 

    public Int32 esize; 

    public IntPtr epayload; 

} 

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

[StructLayout(LayoutKind.Sequential, Size = 4)] 
public struct stats_t 
{ 
    public Int64 datasize; 

    public UInt32 avgdelay; 

    public Int32 esize; 

    public IntPtr epayload; 

    /// dummy member for alignment 
    public UInt32 dummy; 

} 

Обратный вызов подписи является следующее:

int Callback_Proc(stats_t stats, void *user, int final, int error, int code); 

Делегат для обратного вызова имеет следующую подпись:

public delegate int Callback_Proc(stats_t stats, IntPtr user, Int32 final, Int32 error, Int32 code); 

Я задаюсь вопросом, почему фиктивный элемент необходим для того, чтобы получить обратный вызов работать. Без манекена значение final было смещено на Ошибка, а значение Ошибка было смещено на . Спасибо за понимание и надеюсь, что мое объяснение имеет смысл.

+0

Вы компилируете и выполняете как C++, так и C# процесс на одной и той же размерности ОС и компиляции? На первый взгляд, я мог бы предположить, что процесс C++ является 64-битным и 32-битным C#, поэтому IntPtr будет 4 байта против 8 байтов для C++ void *. – SledgeHammer

+0

Возможно, вы находитесь на 64-битной системе, которая требует 64-битных квантов для структур? Есть ли причина, по которой вы не просто используете класс в C#? –

+0

Оба C++ и C# используют один и тот же бит x86. Также есть отдельная сборка для x64 для C++ и C# кода. – rgeorg

ответ

1

Это потому, что размер IntPtr. Я предполагаю, что ваш код на C++ скомпилирован для 64 бит, поэтому размер указателя void *, ожидаемый кодом C++, составляет 8 байтов, но .net имеет очень уродливое предпочтение 32 бита, если вы компилируете для AnyCPU, проект все еще имеет (stupid) с именем «Предпочитайте 32 бита» в параметрах компиляции, поэтому даже если код выполняется на 64-битной машине, он будет работать с 32 битами, что приведет к тому, что указатели будут иметь длину 4 байта.

Извлеките «предпочтительно 32 бит» из проекта или скомпилируйте явно на x64, что должно исправить вашу проблему.

+0

Спасибо, у меня две конфигурации сборки x86 и x64 соответственно. Некоторое время назад я избавился от конфигурации AnyCPU. – rgeorg

+0

может возникнуть проблема в esize, ваш компилятор C++ относится к «int» как «int32» или «int64»? Я говорю «может быть», потому что это может привести к смещению указателя полезной нагрузки и сбою его чтения ... – Gusman

+0

Спасибо, я считаю, что это может быть ответом, потому что перед реализацией фиктивной работы у меня был обратный вызов, работающий с esize как Int64 – rgeorg

Смежные вопросы