.net — Понимание управляемого переполнения стека

У меня проблемы с пониманием того, как работает управляемый C ++ и компилируется.

В .NET Framework вы можете разрабатывать код на C # / VB / F # / .. и т. Д. и все эти языки будут скомпилированы в один и тот же общий промежуточный язык (CIL), который похож на байт-код Java. Теоретически, CIL может быть установлен на любой платформе (Mono сделал это практичным). В Windows CLR компилирует CIL в собственный код Just-In-Time (JIT), и все работает гладко и хорошо.

Как компилируется Managed C ++? Компилируется ли он в код CIL и ждет, пока CLR запустит его с использованием JIT? Я думаю, что нет, потому что Managed C ++ может использовать стандартный код C ++ (который не скомпилирован в CIL). Кроме того, как он может использовать сборки .NET (которые являются CIL)?

Буду признателен за любую помощь.
Спасибо

РЕДАКТИРОВАТЬ:

Я видел это ответ. Он отмечает, что в C ++ / CLI управляемый код компилируется в MSIL, и у вас есть возможность скомпилировать неуправляемый код либо в собственный код, либо в MSIL. Поэтому теперь я понимаю, как возможен вызов сборок .NET.

Во всяком случае, я до сих пор не понимаю, как неуправляемый код C ++ может работать с управляемым кодом в той же сборке, если неуправляемый код был скомпилирован в собственный код. Есть идеи?

4

Решение

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

Кроме того, как он может использовать сборки .NET (которые являются CIL)?

Не только CIL, линкер производит с комбинированным режимом работы сборка. Содержит оба метаданных .NET + msil а также нативный код Фактически, что касается загрузчика ОС, то это обычный код в исполняемом файле, который является нормальным. Ничем не отличается от вида, созданного собственным компилятором C ++. Он загружается и перемещается точно так же, как чистый собственный исполняемый образ. Это метаданные .NET + msil, которые являются чудаком. Для загрузчика это просто выглядит как кусок данных, это совсем не трогает. Только CLR делает.

… использовать стандартный код C ++ (который не скомпилирован в CIL)

Не совсем точный, нативный код C ++ можно скомпилировать в msil или же Машинный код. То, что вы получите, зависит от того, была ли использована опция компиляции / clr или управляемая #pragma, которая действовала на уровне функций. CIL не может сравниться так хорошо, скажем, с байт-кодом, используемым в Java JVM. Он более мощный и может поддерживать любой собственный C ++ 03-совместимый код C ++. Иногда вы делаете это специально, чтобы воспользоваться преимуществами обратного пинвока (нативный код, вызывающий управляемый код). Иногда это делается случайно, и слишком много собственного кода C ++ компилируется в msil. Машинный код, генерируемый джиттером, не столь оптимален (он оптимизируется в условиях ограниченного времени) и никак не управляется. Это не поддается проверке и не получает любовь сборщика мусора.

Лучший мысленный образ для CIL — это промежуточное представление, которое используется в любом встроенном компиляторе C ++ между внешним интерфейсом (синтаксическим анализатором) и внутренним сервером (генератором кода и оптимизатором). Часто невидимая деталь реализации, но становится более заметной, когда вы используете компилятор C ++, который использует LLVM (как это делает Clang). Компилятор .NET точно в срок делает во время выполнения то, что делает LLVM во время компиляции.


У большинства программистов есть мысленный образ гигантского переключателя режимов, возникающего, когда управляемый код вызывает собственный код (или наоборот). Это совсем не точно. Возможно, вы захотите взглянуть на эта почта, показывает разницу между машинным кодом, созданным серверной частью компилятора C ++, и джиттером. Ключевым является то, что он практически идентичен, что существенно для обеспечения того, чтобы управляемый код был конкурентоспособным по сравнению с собственным кодом. Помогает выяснить, как управляемый код, вызывающий нативный код, или наоборот, не такой уж особенный.

Другое заблуждение заключается в том, что управляемый код автоматически безопаснее. Не совсем верно, что язык, такой как C #, позволяет вам использовать указатели и набрасываться в стеке, как вы можете это делать с C ++, и вы можете таким же образом повредить память. Он просто лучше разделен, он заставляет вас быть откровенным с unsafe ключевое слово. Нет таких ограничений на C ++ / CLI, все идет.

Существенным отличием управляемого и собственного кода является структура данных, которую генерирует джиттер при компиляции msil. Дополнительные данные, которые вы не получите от собственного компилятора. Эти данные требуются сборщику мусора, он говорит ему, как найти корни объекта обратно. Подробнее об этих данных в эта почта. Необходимость соответствовать этим данным и позволить GC выполнять свою работу — вот что делает управляемый код немного медленнее во время выполнения.

7

Другие решения

Управляемый C ++ устарел. Сегодня для написания нативного C ++ и управляемого кода вам нужно использовать C ++ \ CLI. Он соответствует CLR и может запускать другие сборки .net. Вы также можете использовать собственный вызов, они отлично подходят для взаимодействия между собственным кодом и кодом .NET
Чтобы вызвать .NET Assembly, добавьте ссылку на ваш проект в эту сборку и добавьте в свой код:

using namespace System;
0