c++ 混合的、纯的和可检验的代码
混合的、纯的和可检验的代码
对于.NET 程序设计来说,Visual C++ 支持创建3种类型的组件和应用程序:混合的(mixed)、纯的(pure)和可检验的(verifiable)。通过使用 /cls 编译选项,便可得到这3种东西。
1.混合的程序集(/clr)
混合程序集(用 /clr 选项编译)包含非托管机器指令和托管MSIL指令。这样就让这些程序集可以调用.NET 组件和被.NET组件斯调用,且保留了与完全非托管代码组件的兼容性。使用混合程序集,开发者可以用托管功能和非托管功能混合编写应用程序。这使得混合程序集适合于从现有的C++ 应用程序迁移到.NET平台上。用这种方式来使用C++ 混合托管和非托管代码称为互操作(Interop)。
例如,一个全部由非托管函数组成的应用程序,可以用/clr选项仅重新编译其中的某一个模块,这样该程序就可以用在 .NET平台上了。因为这个模块能够使用 .NET的特性,且仍然与该应用程序的其余部分保持兼容。通过这种办法,一个应用程序就可以逐步地、一块一块地转换到 .NET平台上。甚至于还可以在一个文件内,一个函数一个函数地采用托管和非托管编译。
注意:/clr 编译选项为编译的函数提供了模块(函数)级的控制,既可按托管方式、也可按非托管方式进行编译。非托管函数只能对本地平台进行编译,且这部分程序执行时也只由CLR传递给本地平台。当使用 /clr 时,函数默认地变成了托管代码。如果编译时没有使用 /clr 选项,编译程序就会不考虑程序是非否添加了托管或非托管的编译指示符。编译指示符应放在编译函数模块的前面,而不是放在函数体内。
当模板函数取实例时,模板定义时的编译指示符决定了它到底是托管的还是非托管的。
例子:
// pragma_directives_managed_unmanaged.cpp
// compile with: /clr
#include <stdio.h>
// func1 is managed
void func1() {
System::Console::WriteLine("In managed function.");
}
// #pragma unmanaged
// push managed state on to stack and set unmanaged state
#pragma managed(push, off) // 参见注释A
// func2 is unmanaged
void func2() {
printf("In unmanaged function.\n");
}
// #pragma managed
#pragma managed(pop)
// main is managed
int main() {
func1();
func2();
}
注释A:为把函数编译成托管的或非托管的,须启用函数级的编译指示功能。如
#pragma managed
#pragma unmanaged
#pragma managed([push,] on | off)
#pragma managed(pop)
输出:
In managed function.
In unmanaged function.
2.纯的(/clr:pure)
纯程序集除包含托管函数外,还可包含本地数据类型和托管数据类型。与混合程序集相似,纯程序集可以通过P/Invoke(参见“在C++ 中使用显式PInvoke(DllImport Attribute)”)与本地 DLL 互操作,但不能使用C++ 的互操作特性。此外,纯程序集不能导出可从本地函数中调用的函数,因为纯程序集中的入口点使用了__clrcall调用约定。
3.可检验的(/clr:safe)
用 /clr:safe 编译选项可生成可检验的程序集,与用 VB 和 C# 编写的程序集一样,它们遵从下述要求:让 CLR 保证代码不违反当前的安全设置。例如,如果安全设置禁止组件写盘,CLR就会在执行代码前决定是否某可检验组件满足这个标准。可检验组件没有 CRT(运行时间库)的支持。(纯程序集对C运行库的所有纯MSIL版本都可以使用 CRT 支持。)其优点是:
● 增强了安全性;
● 某些情况下需要使用它(如SQL组件);
● Windows 的新版本会加强对组件和程序的可检验性要求。
缺点是,不能使用C++的互操作性。可检验程序集不能包含非托管函数或本地数据类型,既使托管代码没有引用它们。
尽管使用了“安全”一词,但用 /clr:safe 编译程序时并不意味着不会产生垃圾;它只是说CLR在运行时会检查安全性设置而已。
与程序集的类型无关,从托管程序集中通过 P/Invoke 调用本地本地DLL会将被编译,但在运行时仍然可能会失败,这取决于安全性设置。