Il est un grand sujet avec des détails de mise en œuvre très graveleux. Difficile de tous les aborder, mais il y a quelques idées fausses dans la question. Adressons-nous à ceux qui pourraient vous aider à passer à l'étape suivante.
De plus, comment peut-il utiliser des assemblages .NET (qui sont CIL)?
Non seulement CIL, l'éditeur de liens produit un ensemble en mode mixte. Contient à la fois les métadonnées .NET + msil et code natif. En fait, en ce qui concerne le chargeur de système d'exploitation, c'est le code natif dans le fichier exécutable qui est normal. Pas différent du type produit par un compilateur C++ natif. Il est chargé et déplacé juste comme une image exécutable native pure. C'est la méta-donnée .NET + msil qui est l'oddball. Pour le chargeur, cela ressemble à un morceau de données, il ne le touche pas du tout. Seul le CLR le fait.
... Utilisez le code C++ standard (non compilé à CIL)
Pas tout à fait précis, le code C++ natif peut être compilé pour MSIL ou code machine. Ce que vous obtenez dépend de l'utilisation de l'option/clr compile ou du #pragma géré au niveau de la fonction. CIL ne compare pas très bien, disons, le bytecode utilisé dans la JVM Java. Il est plus puissant et peut prendre en charge tout code C++ natif compatible C++ 03. Parfois, vous le faites exprès pour profiter du reverse pinvoke (code managé d'appel de code natif).Parfois, cela se fait par accident et le code C++ natif est entièrement compilé en msil. Le code machine produit par la gigue n'est pas optimal (il optimise en fonction des contraintes de temps) et n'est géré en aucune façon. Il n'est pas vérifiable et n'obtient pas l'amour du garbage collector.
La meilleure image mentale de CIL est la représentation intermédiaire utilisée dans tout compilateur C++ natif entre le frontal (parseur) et le back-end (générateur de code et optimiseur). Souvent un détail d'implémentation invisible mais devient plus visible lorsque vous utilisez un compilateur C++ qui utilise LLVM (comme le fait Clang). Le compilateur juste-à-temps .NET fait au moment de l'exécution ce que fait LLVM au moment de la compilation.
La plupart des programmeurs ont l'image mentale d'un commutateur de mode géant étant lancé lorsque le code managé appelle le code natif (ou l'inverse). Ce n'est pas exact du tout. Vous pouvez jeter un oeil à this post, montre la différence entre le code machine produit par le back-end du compilateur C++ et la gigue. La clé est presque identique, une caractéristique essentielle pour s'assurer que le code managé est compétitif avec le code natif. Aide à clarifier comment le code géré appelant le code natif, ou l'inverse, n'est pas si spécial.
Une autre idée fausse est que le code managé est automatiquement plus sûr. Pas tout à fait vrai, un langage comme C# vous permet de faire la fête avec des pointeurs et de gribouiller sur la pile comme vous le pouvez avec C++ et vous pouvez corrompre la mémoire aussi facilement. Il est juste mieux partitionné, il vous oblige à être explicite à ce sujet avec le mot-clé unsafe
. Pas de telles contraintes sur C++/CLI, tout est permis.
La différence essentielle entre le code géré et le code natif est une structure de données que la gigue génère lorsqu'elle compile msil. Données supplémentaires que vous ne recevez pas d'un compilateur natif. Cette donnée est requise par le garbage collector, elle lui indique comment retrouver les racines des objets. Plus d'informations sur ces données dans this post. Devoir se conformer à ces données et permettre au GC de faire son travail est ce qui rend le code managé un peu plus lent à l'exécution. J'apprécie la note à propos de la C++/CLI
Bonne réponse. En particulier: "CIL ne se compare pas très bien à, disons, le bytecode utilisé dans la JVM Java, il est plus puissant et peut supporter n'importe quel code C++ natif compatible C++ 03". Quand j'ai eu un travail Java, j'ai regardé leurs spécifications bytecode et j'ai pleuré! – hoodaticus