9

例如,如果我不应该使用标准库函数printf()putchar()那么如何将字符打印到屏幕上?

有没有一种简单的方法来做到这一点。我对系统调用了解不多,如果我必须使用它们,那么我该如何使用它们?那么任何人都可以建议一种不使用库函数的简单打印方法吗?

4

4 回答 4

17

在标准C中,你不能。C 中定义的唯一 I/O 是通过 C 标准库函数。

在给定的平台上,可能有办法做到这一点:

  • 直接进行内核调用。您可能需要编写一些内联程序集来执行此操作。您可以直接调用 litb write,而无需使用 C 库。获取 C 库的源代码,看看它是如何完成的。
  • 直接写入帧缓冲区。多用户操作系统通常不允许这样做(至少不进行任何库/内核调用)。

除非您正在编写自己的 C 库,否则我不确定您为什么要这样做。

于 2009-01-22T07:15:31.250 回答
7

在 linux 中,您可以使用write系统调用:

write(1, "hello\n", 6); // write hello\n to stdout

如果你不能得到足够的,你可以降低一步,一般调用系统调用:

syscall(__NR_write, 1, "hello\n", 6);

值得了解的是strace,您可以使用它来查看任何特定程序在运行时使用了哪些系统调用。但请注意,对于“一些简单的解析器”,几乎不需要使用原始系统调用。更好地使用c库的功能。

顺便说一句,如果您想在 Windows 中执行上述操作而不使用 c 标准库,请注意 WriteFile 和 GetStdHandle 函数。虽然不会像 linux 解决方案那样 l33t。

于 2009-01-22T07:05:11.600 回答
4

好吧,谢谢大家的回答。我在问题下方的郝先生的评论中找到了一个简单的答案。他的答案是这样的简单程序

Turbo C(DOS程序):

char far* src = (char far*) 0xB8000000L; 
*src = 'M'; 
src += 2; 
*src = 'D'; 

或试试这个:http ://en.wikipedia.org/wiki/Brainfuck :) – //Hao(一小时前)

我在 Turbo C 和它的工作上试过它。我想要一个像这样的简单解决方案,我想接受它作为正确答案,但他(郝)将其作为评论给出,所以我将其粘贴在这里,让其他用户代表他了解并接受它。再次感谢郝先生。

于 2009-01-22T09:20:02.077 回答
2

C 标准库(请参阅https://en.wikipedia.org/wiki/C_standard_library)具有一组输入和输出例程,用于读取和写入各种输入和输出资源。C 标准库通常建立在目标操作系统提供的系统服务和系统调用之上,尽管在没有操作系统的嵌入式微控制器的情况下使用不同的方法。

除了 C 标准库之外,还有其他经常使用的库,例如 POSIX 库(参见https://en.wikipedia.org/wiki/C_POSIX_library)。

我使用术语资源是因为输入请求或输出请求的目标可能是各种各样的不同事物。

  • 磁盘上的文件

  • 网络连接

  • 控制台设备

  • 一个串行通信端口

  • 一个传感器

  • 打印机设备

  • 屏幕上的一个窗口

C 标准库采用的模型与 Unix 操作系统的模型相似,因为所有各种资源都被视为一个设备,您可以从中读取字符或字节流并写入字符或字节流.

在某些情况下,这是抽象允许您忽略资源物理连接的细节。因此,您可以打开 SATA 硬盘、USB 拇指驱动器或网络服务器上的文件。无论打印机是在串行通信端口、USB 端口还是网络打印机上,您都可以打印到打印机。

对于某些类型的资源,例如控制台设备或具有行和列以及可以移动的光标的打印机,您通常会在写入设备的字符内提供光标定位信息。因此,您将输出要在控制台上打印的文本以及将光标定位到您要写入的位置或其他一些操作(例如突出显示文本)的转义码。

一种这样的控制台设备是 DEC 的 VT100 终端(参见https://en.wikipedia.org/wiki/VT100),它在输出中使用特殊的转义码来执行诸如将光标定位在屏幕上的操作。这非常方便,以至于 Unix、Linux 和 Windows 上的控制台窗口使用类似的转义码在控制台或命令窗口上执行类似的操作(请参阅如何使 win32 控制台识别 ANSI/VT100 转义序列?)。

C 标准库为各种设备提供标准接口,由编写库的人员提供库实际进行读写所需的底层功能。

然而,标准库确实有字符流的限制,作为它使用或呈现给程序员的模型的一部分。这就是为什么还有其他库不属于图形用户界面和游戏的 C 标准库的一部分的原因,例如来自 Microsoft、Qt 和各种其他组(例如 OpenGL)(请参阅https://en.wikipedia.org/wiki/ OpenGLhttps://en.wikipedia.org/wiki/DirectXhttps://en.wikipedia.org/wiki/Graphical_user_interface什么是 Linux 的原生 GUI API?)。也请参阅GUI 是如何真正制作的?操作系统如何在屏幕上绘制窗口

如果您想绕过 C 标准库并直接使用操作系统 I/O 系统调用或服务,您可以这样做。然而,与满足 C 标准要求的跨编译器的标准 C 标准库不同,操作系统 I/O 服务将因操作系统而异。并且某些操作系统可能有几种方法来执行相同类型的 I/O。例如,Windows 有许多不同的方式来执行文件 I/O(请参阅https://en.wikipedia.org/wiki/Windows_API)。

在某些情况下,您可以绕过操作系统并直接与设备或资源对话。这通常是通过嵌入式应用程序完成的,在许多情况下,对于某些微控制器上的嵌入式应用程序,没有可用的真正操作系统,您必须直接与设备交互。

微控制器上的嵌入式应用程序通常使用特定的内存地址与传感器交互,以便为传感器做好传感准备以及从传感器读取温度等数据。传感器有许多不同的连接方法,这要求程序员了解电气设置和用于与传感器通信的协议,例如 I2C(参见https://en.wikipedia.org/wiki/I²C), 1-wire(参见https://en.wikipedia.org/wiki/1-Wire)等。

在旧的 MSDOS 操作系统下,您可以调用 BIOS 例程直接与包括屏幕在内的设备进行交互。或者,如果您知道屏幕缓冲区的地址和内存区域的正确格式,您可以通过直接写入屏幕帧缓冲区所在的内存区域来修改屏幕上显示的内容。

现代多线程和多处理操作系统在其系统调用中具有复杂的功能,以处理多个应用程序都试图使用相同的设备和资源时可能出现的各种同步和协调问题。由于 C 标准库是建立在这些操作系统服务之上的,因此当您使用 C 标准库时,您将获得诸如文件锁定之类的复杂功能。通过标准库使用操作系统服务,您可以获得专家的专业知识和知识,他们已经完成了您可以使用的工作。

现代操作系统提供了丰富多样的服务,例如文件 I/O、网络 I/O、打印服务等。C 标准库以及来自其他组的其他库(例如 POSIX)提供了一种标准的、可移植的方式来访问这些服务.

当 C 标准库和 POSIX 库移植到微控制器时,您可以访问相同的功能,而无需编写自己的库的巨大学习曲线。

于 2020-06-29T02:57:03.100 回答