Невозможно получить доступ к переменной из явной структуры (вызов объединения) C #

1

Я пытаюсь построить явную struct С# из C- union. Явная структура:

[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct struct_1
{
   [FieldOffset(0)]
   [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
   public uint[] All32;

   [FieldOffset(0)]
   [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
   public struct_2[] bits;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct struct_2
{
   [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
   public byte[] Var56;
}

Это структуры, и я не могу получить доступ к All32 который является uint после создания экземпляра из массива byte (intellisense показывает "?") Следующим образом

Type structureType = typeof(struct_1);

byte[] b = new byte[4];
b[0] = 0xA0;
b[1] = 0x01;
b[2] = 0xF0;
b[3] = 0x00;

if (structureType != null)
{
   try
   {
      GCHandle handle = GCHandle.Alloc(b, GCHandleType.Pinned);
      struct_1 intpdObj = (struct_1)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), structureType);
      handle.Free();
   }
   catch
   {
   }
}
  • 0
    Ваш пустой блок catch может подавлять ценную отладочную информацию.
  • 0
    У меня нет никаких "?" вопрос. Тем не менее, вот что я получил, ваше первое поле указывает на тот же адрес, что и ваш второй, и находит struct_2 вместо uint (см. Столбец «type» на моем рисунке)
Показать ещё 1 комментарий
Теги:
struct
unions

3 ответа

1

ОК. Это связано с тем, что вы определили массив внутри struct_2 и это объект, поэтому адрес памяти будет помещен внутри этого местоположения, когда PtrToStructure создает структуру. Вы можете попробовать следующее:

[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct struct_1
{
    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.ByValArray)]
    public uint[] All32;

    [FieldOffset(0)]
    [MarshalAs(UnmanagedType.Struct)]
    public struct_2 bits;
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct struct_2
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public byte[] Var56;
}
  • 0
    Благодарю. Но опять та же проблема. Невозможно получить доступ к All32. Похоже, я должен идти по пути, указанному Крисом ниже.
  • 0
    Странно, но у меня это работает без проблем. Console.WriteLine(intpdObj.All32[0]);
Показать ещё 3 комментария
1

MarshalAs не изменит способ представления данных в вашем классе.NET/struct, он просто изменит способ маршализации данных при передаче другому коду. Массив все равно будет ссылкой на массив, и все это превращается в ад там.

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

Возьмите этот союз, например:

[StructLayout(LayoutKind.Explicit)]
public struct ArrayUnion
{
    [FieldOffset(0)]
    public byte[] bytes;

    [FieldOffset(0)]
    public int[] ints;
}

Если я создам новый экземпляр этой структуры со 100-байтовым массивом, массив ints также будет требовать иметь длину 100:

var u = new ArrayUnion { bytes = new byte[100] };
Console.WriteLine(u.ints.Length);

Это, конечно, неверно. Если я попытаюсь получить доступ к чему-либо из первых 25 записей в массиве ints я, вероятно, получу серьезную ошибку и ints краха.

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

  • 1
    Вау, отрывочно. Внезапно небезопасный код кажется не таким уж плохим хе-хе;)
  • 0
    @ Крис Да, есть unsafe код и небезопасный код. Это второй тип: P С другой стороны, это самый быстрый способ преобразования байтового массива произвольной длины обратно в целые числа (или двойные числа, или что угодно), которые он представляет, без использования unsafe . Это хак, но это не будет работать , если вы будете осторожны с ним и знать риски.
0

Почему All32 - массив? Что произойдет, если вы попробуете что-то подобное?

[StructLayout( LayoutKind.Explicit, Pack = 1 )]
public unsafe struct struct_1
{
    [FieldOffset( 0 )]
    public uint All32;

    [FieldOffset( 0 )]
    public fixed byte bits[4];
}

Изменение: если вы хотите, чтобы All32 был массивом:

[StructLayout( LayoutKind.Explicit, Pack = 1 )]
public unsafe struct struct_1
{
    [FieldOffset( 0 )]
    public fixed uint All32[1];

    [FieldOffset( 0 )]
    public fixed byte bits[4];
}
  • 0
    Потому что это действует только в небезопасном коде?
  • 0
    Ну да, но это работает ..! Я бы сказал, что Marshal.PtrToStructure союзов и Marshal.PtrToStructure в C # в любом случае не очень далеко от небезопасной территории кода.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню