C

来自osdev
跳到导航 跳到搜索

C是一种简约的编程语言,它独立于平台,不需要runtime运行时支持。 由于这些特性,它已成为迄今为止操作系统开发和系统编程领域中最常用的语言。 它可以近似为 "更方便的 汇编",因为最初它就是这样设计和使用的。

编译器

由于其极简的特性,因此不需要复杂的编译器来编译C。 因此,已经有许多为C编写的各种编译器,并且许多编译器可以用于OS开发。 今天最常见的两种是 GCC 和微软的VC++。GCC是开源开发中最常见的。

正文: C Library

C库已有实现标准C函数 (即 <stdlib.h> 、 <math.h> 、 <stdio.h> 等头文件中声明的东西),并以二进制形式提供了它们,它们适合与用户空间的应用程序链接。

除了标准C函数 (如ISO标准中定义的) 之外,C库可能 (并且通常会) 实现其他功能,这些功能可能有或没有由某些标准定义。 例如,标准C库对网络没有任何规定。 对于类似Unix的系统,POSIX标准定义了C库的预期内容; 其他系统可能根本不同。

需要注意的是,为了实现其功能,C库必须通过系统调用来调用内核函数。 因此,对于您自己的操作系统,您当然可以使用现成的C库,然后为您的操作系统重新编译它- 但这需要您告诉库如何调用内核函数,并且你的内核要实际提供这些函数功能。

还应注意,您不能直接在内核中使用user mode用户模式的C库,因为内核代码需要专门编译。 诸如malloc,free,memcpy之类的东西需要您在使用之前实现。

C不能做的事情

由于C的平台独立性,因此OS开发的某些部分功能只能在汇编中完成。 可以使用inline Assembly内联汇编实现,但这仍然需要高级语言领域之外的知识。

必须用纯汇编编写的代码规范示例是第一阶段引导加载程序。 如果您选择编写自己的引导加载程序,而不是使用现有的解决方案,如GRUB,那么它必须写在汇编,因为它需要直接操纵某些寄存器; 具体来说,是段选择器和堆栈指针,这在C本身是不可能的。

其它功能,例如加载全局描述符表 (在IA32体系结构上),也需要特殊的操作码,这些操作码在c语言中是不可用的 (但可以在 内联汇编 中实现)。 在 (不太可能) 的情况下,您的编译器不支持内联汇编,您可以选择在单独的汇编文件中编写 “支持函数”。 请注意,我们有一个介绍 examples 的页面,说明如何使用GCC进行基本机器操作。

Interrupt Service Routines (ISRs) 也需要一些特殊的处理,因为它们是由CPU直接调用的,而不是由C环境调用的。

关于优化你应该知道的事情

在某些时候,您可能希望在启用优化的情况下编译代码。 然而,如果你的C代码没有正确编写,这可能会导致不可预测的结果。 你可能会浪费几天或几周试图找出为什么你的代码在没有启用优化的情况下完美地工作,但是一旦你用优化编译它,它就不再工作,甚至崩溃或锁定你的操作系统。 如今,操作系统通常是多线程环境,但是编译器的优化器通常认为算法和内存更改是单线程的,仅对一个实例可见。 因此,如果优化器确定您的代码做了一些多余的事情,并且可以进行优化,则它可能会删除代码或以某种方式更改其逻辑。 这些是对代码的合法更改,但在某些情况下,这不是您想要的,它只会破坏代码。 为防止此类事情发生,请在必要时使用 volatile 关键字。

为了解决由于处理器在运行时执行的优化而导致的可能问题 (例如,重新排序指令和内存访问,缓存内存),请确保在必要时使用 原子操作内存屏障。 然而,这不是特定于C/C++语言的优化,而是特定于平台和硬件的优化。

但是,尽管优化明显增加了C代码中小错误的严重性和数量,但假设编译器是稳定的并且考虑了多线程问题,它们将永远不会破坏正确的C代码。 因此,有时最好在所有不同级别启用优化的情况下进行调试,以确保代码绝对正确。 如果关闭了优化,错误仍然存在,只是不太明显。 一个高质量的发行版项目应该在实现已优化的任何组合同时正常工作,尽管这样做很难随时推进进展。

另见

de:C