Использование указателей и адресов

#c#

#c#

Вопрос:

У меня есть следующий код на C #: (обновление кода / вопроса) Код и проект помечены как небезопасные

 private struct MEMORY_BASIC_INFORMATION
        {
            internal uint BaseAddress;
            internal uint AllocationBase;
            internal uint AllocationProtect;
            internal uint RegionSize;
            internal uint State;
            internal uint Protect;
            internal uint Type;
        }


public unsafe static bool CheckForSufficientStack(long bytes)
{
    MEMORY_BASIC_INFORMATION stackInfo = new MEMORY_BASIC_INFORMATION();

    // originally was
    // IntPtr currentAddr = new IntPtr((uint)amp;stackInfo - 4096);

    GCHandle gh = GCHandle.Alloc(stackInfo, GCHandleType.Pinned);
    IntPtr p = gh.AddrOfPinnedObject();

    //now - this line passes compilation        
    IntPtr currentAddr = new IntPtr((uint)p - 4096);

    // build error in the below line
    VirtualQuery(currentAddr, ref stackInfo, sizeof(MEMORY_BASIC_INFORMATION));

   return ((uint)currentAddr.ToInt64() - stackInfo.AllocationBase) >
                   (bytes   STACK_RESERVED_SPACE);
}
  

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

Это код, который я скопировал, и я был действительно удивлен, узнав, что в c # есть ‘amp;’, но затем сборка не удалась.

Есть идеи, как это решить?

Ошибка теперь для последней строки, когда мы выполняем sizeof(MEMORY_BASIC_INFORMATION)

Комментарии:

1. Вы не можете использовать добавление объекта до того, как вы «закрепили» его в памяти. Причина в том, что в противном случае GC может просто переместить его под ваши ноги.

Ответ №1:

Сначала вы должны «закрепить» объект в памяти, чтобы убедиться, что GC не переместит его, пока вы его используете:

 GCHandle gh = GCHandle.Alloc(stackInfo, GCHandleType.Pinned);
IntPtr p = gh.AddrOfPinnedObject();
  

Получить размер структуры с помощью:

 Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION))
  

Комментарии:

1. Спасибо! это решило первую ошибку (я получаю две одинаковые ошибки для двух разных строк) MEMORY_BASIC_INFORMATION stackInfo = new MEMORY_BASIC_INFORMATION(); GCHandle gh = GCHandle . Alloc(stackInfo, GCHandleType. Закреплено); IntPtr p = gh.AddrOfPinnedObject(); IntPtr currentAddr = новый IntPtr((uint)p — 4096); VirtualQuery(currentAddr, ссылка stackInfo, sizeof(MEMORY_BASIC_INFORMATION)); Вторая ошибка относится к последней строке

2. Не могли бы вы обновить вопрос, чтобы сделать его более понятным?

3. Можно ли перейти от класса к структуре?

4. Отлично. Можно ли поделиться с нами декларацией? Кстати, вы пробовали Marshal.SizeOf()?

5. Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION)) работает для меня и быстро возвращает «28» (что, конечно, равно 4 * 7).

Ответ №2:

Чтобы заставить его работать, вы должны указать, что используете небезопасный код в C # (поскольку, например, ошибка в вычислении может привести к получению неверного адреса). Это обеспечивается unsafe ключевым словом.

 unsafe
{
    IntPtr currentAddr = new IntPtr((uint)amp;stackInfo - 4096);
}
  

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

Комментарии:

1. Сам метод помечен как небезопасный. Разве этого недостаточно?

2. Нет. Причиной amp; является использование.

3. Я обвел все строки с помощью ‘unsfae’ и все еще получаю сообщение об ошибке: (и настройки моего проекта допускают небезопасный код

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

5. Тогда не уверен, что не так. Это устраняет проблему с моей стороны и является единственным логическим объяснением ошибки, которую вы получаете.

Ответ №3:

Исходный код отсюда http://joeduffyblog.com/2006/07/15/checking-for-sufficient-stack-space / прошла компиляция, когда я написал ее внутри нового класса, а не внутри существующего класса, который у меня уже есть… Я понятия не имею, почему это прошло….