Как я проверяю число байтов, использованных структурой?

Если я создаю относительно большую структуру, как я могу вычислить байты, которые она занимает в памяти?

Мы можем сделать это вручную, но если структура является достаточно большой затем, как мы делаем это? Есть ли некоторый блок кода или приложение?

42
задан Peter Mortensen 7 May 2017 в 17:28
поделиться

5 ответов

Вы можете использовать либо оператор sizeof либо SizeOf функцию.
Между этими вариантами есть некоторые различия, подробнее см. в справочных ссылках.

В любом случае, хороший способ использовать эту функцию - иметь общий метод или метод расширения, например, такой:

static class Test
{
  static void Main()
  {
    //This will return the memory usage size for type Int32:
    int size = SizeOf<Int32>();

    //This will return the memory usage size of the variable 'size':
    //Both lines are basically equal, the first one makes use of ex. methods
    size = size.GetSize();
    size = GetSize(size);
  }

  public static int SizeOf<T>()
  {
    return System.Runtime.InteropServices.Marshal.SizeOf(typeof(T));
  }

  public static int GetSize(this object obj)
  {
    return System.Runtime.InteropServices.Marshal.SizeOf(obj);
  }
}
30
ответ дан 26 November 2019 в 23:16
поделиться

Вы можете использовать ключевое слово sizeof () для определяемых пользователем структур, которые не содержат каких-либо полей или свойств, которые являются ссылочными типами, либо использовать Marshal .SizeOf (Type) или Marshal.SizeOf (object) , чтобы получить неуправляемый размер типа или структуры, имеющей последовательный или явный макет .

9
ответ дан 26 November 2019 в 23:16
поделиться

Вы хотите использовать System.Runtime.InteropServices.Marshal.SizeOf () :

struct s
{
    public Int64 i;
}

public static void Main()
{
    s s1;
    s1.i = 10;          
    var s = System.Runtime.InteropServices.Marshal.SizeOf(s1);
}
3
ответ дан 26 November 2019 в 23:16
поделиться

Вы также можете использовать System.Runtime.InteropServices.Marshal.SizeOf () , чтобы получить размер в байтах.

2
ответ дан 26 November 2019 в 23:16
поделиться

Структуры очень долгое время были неприятными зверями в компьютерной инженерии. Их структура памяти очень зависит от оборудования. Чтобы сделать их эффективными, их элементы должны быть выровнены, чтобы ЦП мог быстро читать и записывать их значения без необходимости мультиплексирования байтов для соответствия ширине шины памяти. У каждого компилятора есть своя собственная стратегия упаковки членов, часто управляемая, например, директивой #pragma pack в программе C или C ++.

Это нормально, но скорее проблема в сценариях взаимодействия. Когда один фрагмент кода может делать разные предположения о структуре структуры, чем другой фрагмент, скомпилированный другим компилятором. Вы можете увидеть это в COM, дедушке .NET для программирования взаимодействия. COM имеет очень плохую поддержку обработки структур. Он не поддерживает их как собственный тип автоматизации, но имеет обходной путь через интерфейс IRecordInfo. Это позволяет программе обнаруживать структуру памяти во время выполнения посредством явного объявления структуры в библиотеке типов. Что работает нормально, но довольно неэффективно.

.NET-дизайнеры приняли очень смелое и правильное решение решить эту проблему. Они сделали структуру памяти структуры полностью недоступной для обнаружения. Нет задокументированного способа получить смещение члена. И, в более широком смысле, невозможно определить размер структуры. Всеми любимый ответ, использование Marshal.SizeOf () на самом деле не является решением. Это возвращает размер структуры после ее маршалинга , размер, который вам нужно передать, скажем, Marshal.AllocCoTaskMem () перед вызовом Marshal.StructureToPtr. Это упорядочивает и выравнивает элементы структуры в соответствии с атрибутом [StructLayout], связанным со структурой. Обратите внимание, что этот атрибут не требуется для структур (как и для классов), среда выполнения реализует атрибут по умолчанию, который использует объявленный порядок для членов.

Один очень приятный побочный эффект того, что макет невозможно обнаружить, - это то, что среда CLR может с ним трюкать. При упаковке членов структуры и их выравнивании в макете могут появиться дыры, в которых не хранятся никакие данные. Вызывается байтами заполнения. Учитывая, что макет невозможно обнаружить, среда CLR действительно может использовать отступы. Он перемещает элемент, если он достаточно мал, чтобы поместиться в такое отверстие. Теперь вы фактически получите структуру, размер которой на меньше , чем обычно требуется при объявленном макете структуры. И, в частности, Marshal.SizeOf () вернет неправильное значение размера структуры, оно вернет слишком большое значение.

Короче говоря, нет общего способа получить точное значение размера структуры программно.Лучше всего просто не задавать вопрос. Marshal.SizeOf () даст вам приблизительную оценку, если структура непреобразуема. Если по какой-то причине вам нужно точное значение, вы можете посмотреть сгенерированный машинный код метода, который объявляет локальную переменную типа структуры, и сравнить его с тем же методом без этой локальной переменной. Вы увидите разницу в настройке указателя стека, инструкции «sub esp, xxx» в верхней части метода. Конечно, это будет зависеть от архитектуры, вы обычно получаете большую структуру в 64-битном режиме.

107
ответ дан 26 November 2019 в 23:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: