此代码显示在屏幕上的工作原理如何?

时间:2016-05-22 03:24:24

标签: winapi gcc crash operating-system kernel

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

我查看了代码,但我无法理解。

代码如下:

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;

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

1 个答案:

答案 0 :(得分:2)

在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或MS-DOS模拟器(如DosBox)中运行
  • 将其编译到内核中并在裸机环境(QEMU,Virtualbox,VMWare等)中进行测试。

*ch | 0x0700获取当前字符并按位或将其设置为0x0700。这有效地创建了一个16位字,其中字符位于低8位,0x07位于高8位。

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

中有所描述

Video memory cell

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

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