C++ 编译器执行的某些规则比标准 C 编译器更加严格,而且提供一些能够在驱动程序上下文中安全使用的附加特性。
正是一些“高级的”C++ 特性引起了内核模式代码中的问题,例如非 POD("plain old data",如 C++ 标准所定义)类和继承、模板和异常。这些问题主要是由 C++ 实现和内核环境引起,而不是 C++ 语言的内在属性。
内核模式中没有提供所有的标准库(C 或 C++)。
将 C++ 编译器用于内核模式代码,编译器生成的正确的目标代码未必是您期望的代码,其组织方式也未必是您所期望的。
C++ 比 C 更可能发生这种问题。您必须检查目标代码,以确保与您的期望一致,或者至少能在内核环境中正确工作。
目前可用的 C++ 编译器的输出不能保证在所有平台和版本的内核模式都能工作。代码使用的 C++“高级”特性越多,就越可能出现互操作性问题。
对于那些适合两种语言(C 和 C++)的区域,C++ 代码可能更容易出问题,因为 C++ 编译器做了更多的自动化工作,而且您可能不会意识到它导致了一个问题。 C++ 中更严格的类型检查可能不允许技术上合法但是语义上错误的构造。
涉及类层次结构或模板、异常,或各种形式的动态类型的任何内容都可能不安全。使用这些构造需要对生成的目标代码进行非常仔细的分析。
要使用 C++ 编写驱动程序,必须理解编译器生成的代码,确保目标代码满足内核模式要求,并确保其不会出现本文讨论的问题。
开发人员应该做好阅读目标代码、浏览链接图的准备,以确保数据和代码都位于合适的位置并且仅使用了内核安全的库。检查代码的可分页性、内联函数和正确的程序顺序。
使用 C++ 编写内核模式驱动程序面临的最严重的问题是内存页面的管理,尤其是内存中的代码,而不是数据。
C++ 编译器为非 POD 类和模板生成代码的方式使得很难确定执行一个函数所需的所有代码的去向,因此很难将代码安全地分页。
C++ 编译器没有提供机制来直接控制这些实体在内存中的位置。C++ 的设计并没有考虑控制内存位置的必要性。
C++ 函数的导出基于它们的完整签名,而不是(像 C 函数那样)只基于其名称。因此,无法将 C++ 函数可靠地导出到不同版本的库中,但是可以表示为 extern "C" 的 C++ 函数能够做到。
不是所有的库函数都可以在内核模式下使用,尤其是与“高级” C++ 语言特性相关的函数。
C++ 静态变量(在全局或局部范围内声明)为驱动程序带来了许多问题。
C++ 标准没有指定全局对象的初始化顺序,所以即使存在一种调用全局对象构造函数的机制,初始化顺序也必须由驱动程序明确地控制,或者该顺序无关紧要。
Microsoft 既不认可也不反对使用 C++ 编写内核模式驱动程序。这种保守态度一部分源于本文所述问题,也有一部分源于支持所有平台的需要。在尝试使用 C++ 进行任何内核模式开发之前,您必须清楚本文讲述的已知问题和风险,也应该警惕其他的未知问题。