Буфер фиксированного размера нельзя напрямую использовать из объекта "this" - PullRequest
8 голосов
/ 16 мая 2011

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

[StructLayout(LayoutKind.Sequential, Pack=2)]
unsafe struct ImageDosHeader
{
    ...
    private fixed ushort _e_res[4];
    ...

    [Description("Reserved")]
    [DisplayName("e_res[0]")]
    public ushort e_res_0 { get { ... } set { ... } }

    ...
}

В функциях get / set я пытался сделать следующее, но получаю «Ошибка компилятора CS1666: вы не можете использовать буферы фиксированного размерасодержится в нефиксированных выражениях. Попробуйте использовать фиксированный оператор. "

return this._e_res[0];

Тем не менее, следующая работа:

fixed (ImageDosHeader* p = &this)
    return p->_e_res[0];

ImageDosHeader local = this;
return local._e_res[0];

Я могу легко использовать обходные пути, однако мне интересно, почему непосредственнодоступ к буферу фиксированного размера из этого является незаконным.Или это ошибка, о которой я должен сообщить?

Я использую .NET 2.0.

Ответы [ 2 ]

11 голосов
/ 16 мая 2011

Это из-за базовых инструкций IL.

Программа выполняет эту последовательность инструкций, чтобы получить нужный элемент:

  1. Загрузить адрес в стек.

  2. Загрузить смещение в стек.

  3. Добавьте их.

  4. Считать значение по этому адресу памяти.

Если объект находится в куче, а затем перемещается из-за сборки мусора до шага 4, то адрес, загруженный с шага 1, больше не будет действительным. Чтобы защититься от этого, вам нужно сначала закрепить объект в памяти.

(Тот факт, что вы обращаетесь к структуре с помощью указателя this, означает, что вы понятия не имеете, находится ли структура в куче или в стеке, поэтому вы должны закрепить ее на всякий случай, если она находится в куче .)

Второй пример работает, потому что он копирует структуру в стек , поэтому копия никогда не будет перемещаться, поэтому адрес всегда будет действительным.

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

5 голосов
/ 16 мая 2011

Перспектива, с которой вы смотрите на ключевое слово fixed, меняет его семантику, что довольно запутанно.Первоначальная цель оператора fixed заключалась в том, чтобы закрепить часть блистерной памяти на месте, в C # 2.0 она используется вместе с объявлением поля для обозначения того, что «массив имеет длину ровно N элементов»таким образом, фиксированного размера, не фиксированного в памяти.

Я бы избавился от ключевого слова fixed в объявлении поля и просто использовал бы:

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] private ushort[] _e_res;

Таким образом, структура по-прежнему является blittable и не трудна для работыс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...