【问题标题】:How does this code to display to screen works?这段代码如何显示到屏幕上?
【发布时间】:2016-09-19 02:35:25
【问题描述】:

当我找到真正的操作系统开发教程时,我正在浏览整个 Internet 上的内核开发教程。

我浏览了代码,但我无法理解。

代码如下:

int main(void){

char *str = "Hello, world", *ch;

unsigned short *vidmem = (unsigned short*) 0xb8000;
unsigned i;

for (ch = str, i = 0; *ch; ch++, i++)
    vidmem[i] = (unsigned char) *ch | 0x0700;

for (;;);
}

当我使用 Dev C++ 编译上述代码并生成 Win32 控制台或 Windows 应用程序时,它在我运行时崩溃,它告诉我我的程序“已停止工作”并终止。它似乎在循环中的这一行失败:

vidmem[i] = (unsigned char) *ch | 0x0700;

代码有什么问题,我该如何解决?

【问题讨论】:

  • 它在 for 语句中显示错误 不是问题描述。有 两个 for 语句 - 哪一个导致错误?它显示的是什么确切错误?您的屏幕上就在您面前;您绝对没有理由不在您的问题中包含它,所以我们也有它。
  • 我直接在windows上运行程序。那么会不会出现访问0xB8000的非法内存(内存保护)之类的问题。 windows会允许访问吗?
  • 不,Windows 程序不支持此功能。 Win32 应用程序不能直接访问视频内存。当它更新到 vidmem 时,它可能会导致程序出现故障/崩溃。你真正的问题是 - 为什么我的 Win32 程序在运行时会崩溃?此代码旨在用于裸机环境或 MS-DOS 环境(如果使用以 DOS 为目标并在 DOS 环境或模拟器(如 DosBox)中运行的 TurboC 或 Microsoft-C 编译器编译,它将工作)
  • 所以,我必须编译代码并创建一个引导加载程序来加载文件才能看到输出。对吗?
  • 除了找到一个 20 多年前的旧 16 位 C 编译器,并在 Dosbox 中运行可执行文件(如果您在 64 位 Windows 系统上)- 没有真正简单的大大地。在你的内核中测试它可能是最好的。

标签: winapi gcc x86 kernel osdev


【解决方案1】:

在for循环中:

for (ch = str, i = 0; *ch; ch++, i++)
    vidmem[i] = (unsigned char) *ch | 0x0700;

条件部分*ch指示C 编译器在表达式为true(非零)时继续循环。只要*ch 不是 NUL(\0) 终止字符,表达式就会为 true 并继续循环。当它到达一个为零的字符时,条件表达式将为 false 并且循环退出。它有效地循环遍历一个字符串,直到它到达 NUL 终止字符。

vidmem[i] = (unsigned char) *ch | 0x0700; 崩溃的原因是vidmem 被赋予了显存地址 0xb8000。基于 Win32 的应用程序无法访问此内存,并且操作系统 (Windows) 将使您的应用程序出现故障并显示有关程序不再工作的错误消息。

解决此问题的唯一方法是将其编译为可以用作 MS-DOS 程序的方式:

  • 用 16 位 C 编译器编译并在 MS-DOS 或像 DosBox 这样的 MS-DOS 仿真器中运行
  • 将其编译到您的内核中并在裸机环境(QEMU、Virtualbox、VMWare 等)中进行测试

*ch | 0x0700 获取当前字符并将其按位或运算到 0x0700。这有效地创建了一个 16 位字,字符在低 8 位,0x07 在高 8 位。

这样做是因为您在使用内存区域 0xb8000 的标准彩色文本视频模式中看到的每个字符都由 2 个字节(一个 16 位字)组成。这在Wikipedia article 中有描述:

如果循环中正在处理的当前字符是字母 H (0x48),那么 *ch | 0x0700 将变为 0x0748,然后将其存储在视频显示器上的特定内存位置。

您可能希望了解C 中的位操作。我发现这个tutorial 可能会有所帮助。

【讨论】:

  • 有一个按位或分隔字符和属性为什么?
  • @PantherCoder 我已经更新了我的答案以触及这一点,并提供了一个关于 C 中位操作的教程的链接
  • vidmem[0] 指向地址 0xB800。由于是保护模式代码,是存储8bits还是存储16bits?
  • @PantherCoder vidmem 它被定义为一个 unsigned short * ,其作用类似于指向 unsigned short int 数组的指针。因此 vidmem[i]= 会将每个元素视为无符号短整数。编译器中的 unsigned short 是 2 字节宽(16 位整数),因此每次赋值都会存储 2 个字节
猜你喜欢
  • 2017-11-06
  • 2019-01-27
  • 1970-01-01
  • 1970-01-01
  • 2016-12-17
  • 1970-01-01
  • 2011-09-27
  • 1970-01-01
  • 2013-04-25
相关资源
最近更新 更多