有人可以解释一下如何向C添加额外的功能吗?
例如,C没有输出函数,所以你可以通过包含stdio.h来使用printf(),C不知道如何打开MessageBox,所以你包含并使用MessageBox()等。
但是这个功能是如何实现的?
您是否必须以某种方式使用汇编程序并访问视频RAM以获得输出或类似内容?
我知道MessageBox()是WinAPI的一部分,但它是如何实现的(尽管WinAPI是用C实现的)?
答案 0 :(得分:7)
与系统交互的任何功能都是通过系统调用机制执行的。从本质上讲,它提供了代码和操作系统之间的接口。您提到的库函数围绕各种系统调用包含一些方便的功能,以便您的代码更容易在更高级别与系统交互。但是,您可以编写代码来直接执行此操作。有关详细信息,请查找syscall和ioctl函数。在Windows上,有更多系统调用,它们分散在Windows API中的各个库中。 Windows系统调用上的Dr. Dobb's article详细介绍了
答案 1 :(得分:3)
意识到你所做的一切都会导致CPU从某个存储器地址读取数字,对它们执行一些计算,或者将它们写入某个存储器地址。
因此,与外界的大多数通信 - 视频卡,网卡等设备 - 基本上归结为读取或写入魔术记忆位置。
(这有点过于简单化,CPU可以做的其他一些事情 - 它可以读/写数字的I / O端口等;这些不能直接从标准C访问,通常是C库暴露这样的功能将使用汇编程序编写相关代码;但现在让我们使用它。)
用C语言编写的硬件驱动程序通常使用熟悉的C类型声明描述内存映射区域布局的struct
,获取相关区域的地址,执行适当的转换然后只使用生成的指针任何其他人。
操作系统通常将这种特定于硬件的代码包装在某种提供虚拟化的机制中(因此您的代码可以假装它正在与某些标准的理想化设备进行通信,并且操作系统会在它与实际内容之间进行转换)机器)和权限分离(因此,您的代码无法执行它不应该和/或崩溃其他人的代码)。因此,您链接到的库将不会直接与硬件通信;他们将调用操作系统(通常使用某种形式的系统调用/中断/异常机制),这将为他们做到这一点。但操作系统本身将大致完成我上面描述的内容。
答案 2 :(得分:2)
对于printf部分 - 它是C标准库的一部分,它是C的一部分。因此,C编译器或C标准库的实现可以使用所有类型的技巧来使其工作。
让我们举一个简单的例子来说明如何在Unix中实现这样的功能。取putchar
(此处简化 - 不返回任何内容)。它将一个字符输出到标准输出,其具有文件描述符编号1.操作系统提供称为“写入”的功能。程序可以写入文件描述符。所以,putchar可以使用该功能:
void putchar(int c) {
unsigned char cc = c;
write(1, &cc, 1);
}
将1个字节写入文件描述符1.写入函数将告诉操作系统该愿望:
void write(int fd, void * ptr, size_t size) {
asm("....."
"int 0x80");
}
它通常只包含一小段装配线,它会引发软件中断(在上面的示例中,它是中断号0x80)。 CPU将切换到内核模式并跳转到某个固定地址,操作系统可以从中处理该中断。 write
将写入系统调用号以写入某个寄存器,并将参数放入某个内存位置或寄存器中,以便操作系统知道该做什么。然后操作系统将发送应写入指定文件/设备的字节(在stdout的情况下,它可能是连接到文件描述符的终端驱动程序),并将从中断返回,使CPU切换到用户模式。
这是粗略的计划。还有更多内容(putchar可以在进行系统调用之前缓冲输出......)。但原则上它以这种方式工作。
MessageBox函数最终也会调用一些系统调用,它会以某种或其他方式将控制转移到windows内核中,类似于上面的解释。
答案 3 :(得分:1)
首先,你有C编译器,它符合ANSI C标准。这是语言本身,不包括库。
然后你有了标准库,你可以找到你提到的printf函数。这是使用C和ASM构建的,并且是特定于平台的。例如,在嵌入式平台中,printf会将字符打印到串行端口或液晶显示器。因此需要使用特定于平台的代码。但是,该界面适用于所有平台。
与第三方库类似的事情,如WinAPI。
答案 4 :(得分:0)
通常,库是用“C”编写的。大多数Win32 api都是用C语言编写的。有些东西你不能直接在C中表达,比如'syscall','int'和读/写io ports。
看一下K&R他们实际上在书中实现了一些系统库。