Gcc 内核主函数中这个神秘的字符是什么?我怎样才能删除它?

Gcc 内核主函数中这个神秘的字符是什么?我怎样才能删除它?,gcc,terminal,x86,kernel,osdev,Gcc,Terminal,X86,Kernel,Osdev,我正试图按照链接创建自己的内核 作者提到“后面跟着一些神秘的人物。” 为什么会出现这个角色?我怎样才能删除它 我正在使用kernel.c文件,只是将kernel main更改为打印ASCII字符 void kernel_main(void) { terminal_initialize(); terminal_writestring(" ____ ___ ____"); termina

我正试图按照链接创建自己的内核 作者提到“后面跟着一些神秘的人物。” 为什么会出现这个角色?我怎样才能删除它

我正在使用kernel.c文件,只是将kernel main更改为打印ASCII字符

void kernel_main(void) 
{
    terminal_initialize();

    terminal_writestring(" ____                         ___  ____");
            terminal_putchar('\n');
    terminal_writestring("|  _ \\ _   _ _ __ ___   __ _ / _ \\/ ___|");
            terminal_putchar('\n');
    terminal_writestring("| |_) | | | | '_ ` _ \\ / _` | | | \\___ \\");
            terminal_putchar('\n');
    terminal_writestring("|  __/| |_| | | | | | | (_| | |_| |___) |");
            terminal_putchar('\n');
    terminal_writestring("|_|    \\__,_|_| |_| |_|\\__,_|\\___/|____/");
            terminal_putchar('\n');
}
这是我的结果
@Ken Y-N是正确的,因为您应该编写
\r\N
而不是
\N
(即,CRLF而不是LF)

然而,更好的解决方案(我认为)是:

a) 检查字符是否为
终端putchar
中的
\n
,是否只是将
终端列
设置为0,并将
终端行
增加一个:

void terminal_putchar(char c) 
{
    /* check that the previous character wasn't a '\r', if it was print CRLF as normal */
    if (c == '\n' && terminal_buffer[terminal_column * VGA_WIDTH + terminal_row] != '\r') {
        /* move cursor to start of next line (without printing a CRLF) */
        terminal_column = 0;
        terminal_row += 1;
        return;
    }
    terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
    if (++terminal_column == VGA_WIDTH) {
        terminal_column = 0;
        if (++terminal_row == VGA_HEIGHT)
            terminal_row = 0;
    }
}
或者更好的方法是b)检查字符是否在
终端\u putchar
\n
,如果是,则打印CRLF:

void terminal_putchar(char c) 
{
    /* turn LF -> CRLF if missing CR */
    if (c == '\n' && terminal_buffer[terminal_column * VGA_WIDTH + terminal_row] != '\r') {
        terminal_putentryat('\r', terminal_color, terminal_column, terminal_row);
    }
    terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
    if (++terminal_column == VGA_WIDTH) {
        terminal_column = 0;
        if (++terminal_row == VGA_HEIGHT)
            terminal_row = 0;
    }
}
希望有帮助

编辑:对于一些额外的优化,您可以检测一个
\r
并设置一些布尔可用值(例如一个1或0的int),然后用该布尔可用值的名称替换
终端缓冲区[terminal\u column…
。这允许保证4字节对齐的访问,这总是更快(有关更多信息,请参阅)。示例代码:

uint8_t was_cr = 0;

void terminal_putchar(char c) 
{
    /* turn LF -> CRLF if missing CR */
    if (c == '\n' && !was_cr) {
        terminal_putentryat('\r', terminal_color, terminal_column, terminal_row);
    }

    /* at this point was_cr has already been read */
    /* considering that was_cr is read every time this function is called, */
    /* it is likely that the CPU will cache it's value, so read times will be short */
    /* even if it isn't cached, memory reads are always faster than memory writes */
    if (c == '\r' && !was_cr) was_cr = 1;
    else if (was_cr) was_cr = 0;

    terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
    if (++terminal_column == VGA_WIDTH) {
        terminal_column = 0;
        if (++terminal_row == VGA_HEIGHT)
            terminal_row = 0;
    }
}

@Ken Y-N是正确的,因为您应该编写
\r\N
而不是
\N
(即CRLF而不是LF)

然而,更好的解决方案(我认为)是:

a) 检查字符是否为
终端putchar
中的
\n
,是否只是将
终端列
设置为0,并将
终端行
增加一个:

void terminal_putchar(char c) 
{
    /* check that the previous character wasn't a '\r', if it was print CRLF as normal */
    if (c == '\n' && terminal_buffer[terminal_column * VGA_WIDTH + terminal_row] != '\r') {
        /* move cursor to start of next line (without printing a CRLF) */
        terminal_column = 0;
        terminal_row += 1;
        return;
    }
    terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
    if (++terminal_column == VGA_WIDTH) {
        terminal_column = 0;
        if (++terminal_row == VGA_HEIGHT)
            terminal_row = 0;
    }
}
或者更好的方法是b)检查字符是否在
终端\u putchar
\n
,如果是,则打印CRLF:

void terminal_putchar(char c) 
{
    /* turn LF -> CRLF if missing CR */
    if (c == '\n' && terminal_buffer[terminal_column * VGA_WIDTH + terminal_row] != '\r') {
        terminal_putentryat('\r', terminal_color, terminal_column, terminal_row);
    }
    terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
    if (++terminal_column == VGA_WIDTH) {
        terminal_column = 0;
        if (++terminal_row == VGA_HEIGHT)
            terminal_row = 0;
    }
}
希望有帮助

编辑:对于一些额外的优化,您可以检测一个
\r
并设置一些布尔可用值(例如一个1或0的int),然后用该布尔可用值的名称替换
终端缓冲区[terminal\u column…
。这允许保证4字节对齐的访问,这总是更快(有关更多信息,请参阅)。示例代码:

uint8_t was_cr = 0;

void terminal_putchar(char c) 
{
    /* turn LF -> CRLF if missing CR */
    if (c == '\n' && !was_cr) {
        terminal_putentryat('\r', terminal_color, terminal_column, terminal_row);
    }

    /* at this point was_cr has already been read */
    /* considering that was_cr is read every time this function is called, */
    /* it is likely that the CPU will cache it's value, so read times will be short */
    /* even if it isn't cached, memory reads are always faster than memory writes */
    if (c == '\r' && !was_cr) was_cr = 1;
    else if (was_cr) was_cr = 0;

    terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
    if (++terminal_column == VGA_WIDTH) {
        terminal_column = 0;
        if (++terminal_row == VGA_HEIGHT)
            terminal_row = 0;
    }
}

请发布
终端\u writestring()
的代码,但我认为问题在于它将
'\r\n'
写入,而不是仅将
'\n'
写入行尾。问题是奇数符号是与
\n
相关联的字符(换行符)。字符集为。从输出中可以清楚地看出,您的代码将
\n
视为
\r\n
(换行和回车)当它转到下一行的第一列时。如果这是您想要的行为,那么您所要做的就是更新光标位置,但扔掉
\n
而不是打印它。您的代码当前正在打印
\n
并将光标更新到下一行的开头。您不需要的其他字符nt直接打印到屏幕上-制表符(\t)、回车符(\r)、换行符(\n)、退格符(\b)。所有这些都必须经过特殊处理。您能给我们展示terminal\u putchar函数的代码吗?请发布
terminal\u writestring()的代码
,但我认为问题在于它写的是
'\r\n'
,而不是仅仅在行尾写
'\n'
。问题在于奇数符号是与
\n
(换行符)相关联的字符。字符集是。从输出中可以清楚地看出,代码将
\n
视为
\r\n
(换行和回车)当它转到下一行的第一列时。如果这是您想要的行为,那么您所要做的就是更新光标位置,但扔掉
\n
而不是打印它。您的代码当前正在打印
\n
并将光标更新到下一行的开头。您不需要的其他字符nt直接打印到屏幕-制表符(\t)、回车符(\r)、换行符(\n)、退格符(\b)。所有这些都必须经过特殊处理。你能给我们看一下terminal_putchar函数的代码吗?我认为问题的真正关键是@MichaelPetch在评论中指出的:当你检测到新行时,你不必将其复制到屏幕上,只需移动光标。你在回答的文本中没有提到这一点,只有一个小的共点如果您不打算在字符串中包含
\n
,您可以为终端换行设置一个单独的函数,不必检查任何内容,只需重置列和递增的行。如果您确实想以writestring/putchar处理
\n
,那么可以在调用程序中利用它。@PeterCordes Hi,感谢我的想法,我正在逐字打印“\n”,如何省略转义序列(\n、\r、\t等)并像往常一样处理代码?是否使用字符串功能等?-复制strlen-2(\n)要设置缓冲区,然后打印缓冲区?@varun_koganti:显然,最简单的方法是一次循环字符串1个字节,并检查特殊情况,否则只能复制字符并更新列。例如,对每个字符分别使用writestring调用putchar。这将处理出现
\n
的情况OD> > R\N\/COD>在字符串的中间。如果您想同时优化多个字节,则可以使用SIMD(MMX或SSE2<代码> PCMPEQB <代码> />代码> MMYCMPEQEYE8E](/代码>),如果您启用SSE指令,则可以同时检查多个字节以在可打印ASCII范围内。(通常内核不)我认为问题的真正关键是@MichaelPetch在评论中指出的:当你检测到一个换行符时,你不必将它复制到屏幕上,只需移动光标。你在回答的文本中没有提到,一个代码块中只有一个小注释。我想,如果你不想在字符串中包含
\n
,你可以e终端换行符的单独函数