什么样的C是写在一个操作系统?

这是有道理的,像一个操作系统的东西会写在C.但是,它有多less,什么样的C? 我的意思是,在C中,如果你需要一些堆内存,你可以调用malloc。 但是,操作系统甚至一堆? 据我所知,malloc 要求操作系统的内存 ,然后将其添加到链表或二叉树,或其他东西。 怎么样一个调用堆栈? 操作系统负责设置其他应用程序使用的所有东西 ,但是它是如何实现的? 当你想用C打开或创build一个文件时,相应的function会向操作系统询问该文件。 那么…那个电话的另一端是什么样的C? 或者在内存分配的另一端?

另外,一个操作系统实际上可以用C编写多less? 所有的? 依赖于架构的代码是什么? 那么更高层次的抽象层次呢 – 是否会用C ++等高级语言编写?

我的意思是,我只是出于好奇而问这个问题。 我现在正在下载最新的linux内核,但是这是永远的。 我不确定是否能够遵循代码 – 或者如果我将陷入一个我从未见过的复杂networking。

什么样的C?

主要是ANSI C,有很多时间考虑它生成的机器码。

但是,操作系统甚至有一堆?

Malloc向操作系统请求一个指向允许使用的内存的指针。 如果一个运行在OS(用户模式)上的程序尝试访问它不拥有的内存,将会导致分段错误。 允许操作系统直接访问系统上的所有物理内存,malloc不需要,任何存在的地址都不会出现seg-fault。

怎么样一个调用堆栈?

调用堆栈实际上通常在硬件级别上运行,并带有一个链接寄存器。

对于文件访问,操作系统需要访问磁盘驱动器,这需要知道如何读取磁盘上的文件系统(有很多不同的种类)有时操作系统有一个内置的,但我认为这是更常见引导装载程序把它交给一个开始,并加载另一个(更大)。 磁盘驱动程序可以访问物理磁盘的硬件IO,并从中build立。

优秀的问题,所有。 答案是:用于编写操作系统的C的“方言”中不存在标准C库。 例如,在Linux内核中,标准的内存分配函数malloc,nmalloc,free等被特殊的kernel-internel内存分配函数kmalloc和kfree所替代,特别限制了它们的使用。 操作系统必须提供自己的“堆” – 在Linux内核中,分配给内核使用的物理内存页面必须是不可分页的,并且通常在物理上是连续的。 请参阅这本关于kmalloc和kfree的linux期刊文章 。 同样,操作系统内核维护自己的特殊调用栈,使用它需要GCC编译器的特殊支持。

另外,一个操作系统实际上可以用C编写多less? 所有的?

就我所知,操作系统绝大多数都是用C语言编写的。一些特定于架构的特性是用汇编语言编写的,但通常很less用来提高可移植性和可维护性:Linux内核有一些汇编器,但是尽量减less它可能。

依赖于架构的代码是什么? 那么更高层次的抽象层次呢 – 是否会用C ++等高级语言编写?

通常内核将用纯C编写,但是有时候更高级的框架和API是用更高级的语言编写的。 例如,MacOS上的Cocoa framework / API是用Objective C编写的,而BeOS的更高级别的API是用C ++编写的。 很多微软的.NET框架都是用C#编写的,“C ++和汇编语言混合编写”Common Language Runtime“。 在Linux上最常使用的QT小部件集是用C ++编写的。 当然,这引入了关于什么被称为“操作系统”的哲学问题。

Linux内核绝对值得关注,但是,必须说,任何人从头开始阅读都是巨大而令人恐惧的。

C是一种非常低级的语言,你可以直接做很多事情。 任何C库方法(如malloc,printf,crlscr等)都需要首先实现,从C中调用它们(例如,看看libc的概念)。 我将在下面举一个例子。

让我们看看C库方法是如何实现的。 我们将以clrscr为例。 当你实现这种方法时,你将直接访问系统设备。 例如,对于clrscr(清除屏幕),我们知道video内存驻留在0xB8000。 因此,要写入屏幕或清除它,我们首先分配一个指向该位置的指针。

在video.c

 void clrscr() { unsigned char *vidmem = (unsigned char *)0xB8000; const long size = 80*25; long loop; for (loop=0; loop<size; loop++) { *vidmem++ = 0; *vidmem++ = 0xF; } } 

现在让我们写我们的迷你内核。 当控制权从引导程序移交给我们的'内核'时,这将清除屏幕。 在main.c中

 void main() { clrscr(); for(;;); } 

为了编译我们的'内核',你可以用gcc把它编译成一个纯的bin格式。

 gcc -ffreestanding -c main.c -o main.o gcc -c video.c -o video.o ld -e _main -Ttext 0x1000 -o kernel.o main.o video.o ld -i -e _main -Ttext 0x1000 -o kernel.o main.o video.o objcopy -R .note -R .comment -S -O binary kernel.o kernel.bin 

如果您注意到上面的ld参数,您会看到我们将内核的默认加载位置指定为0x1000。 现在,您需要创build一个引导装载程序。 从你的启动加载器逻辑,你可能想要把控制权交给你的内核

 jump 08h:01000h 

您通常在Asm中编写引导加载程序逻辑。 甚至在此之前,你可能需要看看如何一个电脑启动 – 点击这里 。

最好从较小的操作系统开始探索。 看到这个滚你自己的操作系统教程

http://www.acm.uiuc.edu/sigops/roll_your_own/

但是它有多less,以及什么样的C?

一些零件必须以assembly方式书写

我的意思是,在C中,如果你需要一些堆内存,你可以调用malloc。 但是,操作系统甚至有一堆? 据我所知,malloc要求操作系统的内存,然后将其添加到链表或二叉树,或其他东西。

一些操作系统有一堆。 在最底层,它们是被称为页面的记忆块。 您的C库然后用malloc以可变大小的方式分区自己的scheme。 您应该了解虚拟内存,这是现代操作系统中常见的内存scheme。

当你想用C打开或创build一个文件时,相应的function会向操作系统询问该文件。 那么…那个电话的另一端是什么样的C?

你调用汇编程序来查询硬件指令,如IN和OUT。 使用原始内存访问时,有时候会有专门用于与硬件进行通信的内存区域。 这被称为DMA。

我不确定是否能够遵循代码 – 或者如果我将陷入一个我从未见过的复杂networking。

是的你将会。 你应该先拿起硬件和操作系统的书。

我的意思是,在C中,如果你需要一些堆内存,你可以调用malloc。 但是,操作系统甚至有一堆? 据我所知,malloc要求操作系统的内存,然后将其添加到链表或二叉树,或其他东西。 怎么样一个调用堆栈?

在你的问题中,你所说的很多内容实际上是由用户空间中的运行时库完成的。

所有操作系统需要做的就是把程序加载到内存中并跳到它的入口点,之后的大部分细节都可以通过用户空间程序完成。 堆和堆只是进程虚拟内存的一部分。 堆栈只是一个在cpu中的指针寄存器。

分配物理内存是在操作系统级别完成的。 OS通常分配固定大小的页面,然后将其映射到用户空间进程。

您应该阅读Linux设备驱动程序3 。 它很好地解释了linux内核的内部。

我不会开始阅读Linux内核,这对于初学者来说太复杂了。

Osdev是一个很好的开始阅读的地方。 我从Osdev那里获得了一些关于学校学科的信息。 它运行在vmware,bochs和qemu上,所以很容易testing。 这里是源代码 。

传统上,由于与硬件交互,内核和设备驱动程序通常需要C语言。 但是,像C ++和Java这样的语言可以用于整个操作系统

欲了解更多信息,我发现Andrew Tannenbaum的操作系统devise和实现特别适用于大量代码示例。

malloc和内存pipe理函数不是C中的关键字。这是标准操作系统库的function。 我不知道这个标准的名字(它不太可能是POSIX标准 – 我还没有发现任何提及),但它是存在的 – 你在大多数平台的C应用程序中使用malloc。

如果你想知道Linux内核是如何工作的,请参考这本书http://oreilly.com/catalog/9780596005658/ 。 我认为这是很好的解释,插入一些C代码:)。