我只是好奇为什么驱动程序和固件几乎总是用C或汇编编写,而不是C++?
我听说有技术原因.
有谁知道这个?
很多爱,路易丝
因为在大多数情况下,操作系统(或"运行时库")提供了C++所需的stdlib功能.
在C和ASM中,您可以创建不包含外部依赖项的裸可执行文件.
但是,由于Windows确实支持C++ stdlib,因此大多数Windows驱动程序都是用C++(有限的子集)编写的.
此外,当固件写入ASM时,通常是因为(A)正在执行的平台没有C++编译器或(B)存在极端的速度或大小限制.
请注意,(B)自2000年初以来一直不是一个问题.
内核中的代码在与用户空间不同的环境中运行.没有进程分离,因此错误很难从中恢复; 异常几乎是不可能的.存在不同的内存分配器,因此在内核上下文中获取new
和delete
正常工作可能更困难.可用的标准库较少,因此有效地使用C++等语言会更加困难.
Windows允许在内核驱动程序中使用非常有限的C++ 子集 ; 基本上,那些可以简单地转换为C的东西,例如除了块开头之外的地方的变量声明.他们建议不要使用new
和delete
,并且不支持RTTI或大多数C++标准库.
Mac OS X使用I/O Kit,这是一个基于C++有限子集的框架,尽管据我所知,它比Windows上允许的更完整.它本质上是C++,没有例外和RTTI.
大多数类Unix操作系统(Linux,BSD)都是用C语言编写的,我认为没有人真正看到过向内核添加C++支持的好处,因为内核中的C++通常非常有限.
1)"因为它总是这样" - 这实际上解释得比你想象的要多 - 因为几乎所有当前系统上的API最初写入基于C或ASM的模型,并且考虑到许多先前的代码存在于C和ASM,通常更容易"顺其自然"而不是弄清楚如何利用C++.
2)环境 - 要使用C++的所有功能,您需要一个完整的运行时环境,其中一些只是提供给驱动程序的痛苦.如果你限制你的功能集会更容易,但除此之外,如果你没有太多的堆,内存管理可以在C++中变得非常有趣.在这种环境中,例外也很有趣,RTTI也是如此.
3)"我看不出它的作用".任何技术熟练的程序员都可以查看一行C并且很清楚在机器代码级别发生了什么以实现该行.显然,优化会有所改变,但在大多数情况下,您可以分辨出正在发生的事情.在C++中,给定运算符重载,构造函数,析构函数,异常等,很难知道在给定的代码行上会发生什么.在编写设备驱动程序时,这可能是致命的,因为您经常必须知道您是否要与内存管理器进行交互,或者代码行是否影响(或依赖于)中断级别或屏蔽.
完全有可能使用C++在Windows下编写设备驱动程序 - 我自己完成了.需要注意的是,您必须注意使用哪些C++功能以及使用它们的位置.
除了更广泛的工具支持和硬件可移植性之外,我认为没有令人信服的理由将自己限制在C语言之外.我经常看到用C语言完成的复杂的手工编码,在C++中可以更自然地完成:
分组为仅在同一数据结构上工作的函数(非通用)的"模块"(通常称为"对象") - >使用C++类.
使用"句柄"指针使模块函数可以使用数据结构的"实例" - >使用C++类.
使用类似函数的宏 - > C++模板和内联函数
不同的运行时行为取决于具有手工制作的vtable("描述符")或使用switch语句调度的类型ID - > C++多态
易于出错的指针算法,用于从/向通信端口编组/解组数据,或使用非可移植结构 - > C++流概念(不一定是std :: iostream)
为了避免名称冲突,将所有内容排除在地狱之外:C++命名空间
上面描述的C++特性都不比手写的C实现花费更多.我可能会错过更多.我认为C在这个领域的惯性更多地与C主要使用有关.
当然,您可能无法在受限环境中自由地(或根本不)使用STL,但这并不意味着您不能将C++用作"更好的C".
使用C而不是说极其谨慎的Java的最大原因是,很容易看到用于给定操作的内存.C非常面向寻址.编写内核代码的关键问题是避免在不方便的时刻引用可能导致页面错误的内存.
可以使用C++,但前提是运行时特别适用于在隐式调用运行时机制时仅引用固定内存中的内部表(不可分页),例如在调用虚函数时使用vtable.这种特殊的改编在大多数情况下并不是"开箱即用"的.
将C与平台集成更容易,因为它很容易剥离其标准库的C并完全保持对内存访问的控制.那么它也是一种众所周知的语言,它通常是内核工具设计者的选择.
编辑:删除对新呼叫和删除呼叫的引用(这是错误的/误导性的); 取而代之的是更为通用的"运行时机械"这句话.
使用C而不是C++的原因是:
因为C++比较慢
或者因为c-runtime已经存在.
这是因为C++使用异常.大多数C++语言异常的实现在驱动程序代码中都是不可用的,因为当OS响应硬件中断时会调用驱动程序.在硬件中断期间,不允许驱动程序代码使用异常,因为这会导致递归中断.此外,在中断的上下文中可用于代码的堆栈空间通常非常小(并且由于无例外规则而不可增长).
您当然可以使用new(std :: nothrow),但由于c ++中的异常现在无处不在,这意味着您不能依赖任何库代码来使用std :: nothrow语义.
这也是因为C++放弃了C的一些功能: - 在驱动程序中,代码放置很重要.设备驱动程序需要能够响应中断.中断代码必须放在"非分页"的代码段中,或永久映射到内存中,因为如果代码在分页内存中,它可能在被调用时被分页,这将导致异常,这是被禁止的.在用于驱动程序开发的C编译器中,有#pragma指令可以控制最终的哪种类型的内存函数.由于非分页池是非常有限的资源,因此您不希望将整个驱动程序标记为非分页:但是C++会生成大量隐式代码.例如,默认构造函数.没有办法将C++隐式生成的代码括起来来控制它的位置,
因此,总结一下: - C,而不是C++用于驱动程序开发的原因是因为用C++编写的驱动程序会消耗不合理数量的非分页内存,或者使操作系统内核崩溃.
我遇到的评论是为什么一家商店将C用于嵌入式系统而不是C++:
C++产生代码膨胀
C++异常占用了太多空间.
C++多态和虚拟表使用太多内存或执行时间.
店里的人不懂C++语言.
唯一有效的理由可能是最后一个.我见过包含OOP,函数对象和虚函数的C语言程序.它非常快速变得非常丑陋并使代码膨胀.
如果正确实现,C中的异常处理会占用大量空间.我会说与C++相同.C++异常的好处:它们在语言中,程序员不必重新设计轮子.
我更喜欢嵌入式系统中C++到C的原因是C++是一种更强大的类型语言.在编译时可以找到更多问题,这缩短了开发时间.此外,C++是一种比C更容易实现面向对象概念的语言.
反对C++的大多数原因都是围绕设计概念而不是实际语言.
C非常接近机器独立的汇编语言.大多数OS类型的编程都处于"裸机"级别.使用C,您读取的代码是实际代码.C++可以隐藏C不能的东西.
这只是我的意见,但我花了很多时间在我的生活中调试设备驱动程序和操作系统相关的事情.通常通过查看汇编语言.在低级别保持简单,让应用程序级别变得有趣.