【问题标题】:extended ASCII characters not working in int 10h扩展的 ASCII 字符在 int 10h 中不起作用
【发布时间】:2019-05-15 00:45:36
【问题描述】:

我有一个简单的操作系统(实模式),用 NASM(仅引导加载程序)和大多数 C 语言编写。

我想打印这个字符:ñ,我使用这个函数,它使用 int 10h 将一个字符打印到屏幕上:

void putch(char chr)
{
    __asm__ __volatile__ ("int $0x10"
                          :
                          : "a" ((0x0e<<8) | chr),
                            "b" (0x0000));
}

void println(char *str)
{
    while (*str)
        putch(*str++);
}

现在,我尝试打印ñ:

println("ñ\r\n");

但是当我编译和执行时(在 qemu 和 VB 框中),字符“ñ”被忽略了。 我以 CP-437 编码保存了源代码,但问题仍然存在。 这也会影响所有扩展的 ASCII 字符。

【问题讨论】:

  • @usr2564301 我已经编辑过 - 很明显这里是 int 10h,0Eh。

标签: c x86 nasm bootloader bios


【解决方案1】:

问题很简单。在 x86 编译器中,charsigned'ñ',即0xA4 被认为是负数 (-92)。签名的char 被提升为int(通常的算术提升),用于|。这通过符号扩展发生。

结果值当然是 -92 (0xFFA4),|ed 和 0x0E00 将导致 0xFFA4... 这意味着我们现在不是函数 AH=0Eh调用函数 AH=FFh... 如果它存在的话。

一种解决方案是让putch 将参数作为int 并将其转换为unsigned char,就像C 函数putchar & al做:

void putch(int chr)
{
    __asm__ __volatile__ ("int $0x10"
                          :
                          : "a" ((0x0e<<8) | (unsigned char)chr),
                            "b" (0x0000));
}

或者只是让它接受参数作为 unsigned char,就像 cmets 中建议的那样。

【讨论】:

  • 详细信息:1)“在 x86 字符已签名。” --> 使char 签名的不是处理器,而是编译器。 2)“ñ将被提升为负整数”就像有效的结果一样,但是"ñ"编码为char使str[0]为负-尚未涉及int。在(0x0e&lt;&lt;8) | chr 中从charint 的提升没有改变值。 3) 使用putch(int chr) 代替putch(char chr) 是个好主意,但putch(char chr) 会产生相同的结果。
  • @chux :在原来的 ((0x0e&lt;&lt;8) | chr) 中,chr 不会被提升为有符号整数。如果它是负数,它会将符号扩展到整个int 并对其进行 0x0e00 处理?这应该产生了 Anti 所指的效果,即在促销时将 8-15 位设置为 1,因此与它们进行任何运算仍然保持 8-15 位设置。最后你得到的值是 0xFF??
  • @MichaelPetch 是的,效果就像您评论的那样,但对我来说,步骤的解释听起来像是当传递的值已经为负时,促销使值变为负。
  • 我会将它定义为void putch(unsigned char) 以指定我们想要零扩展,并让调用者知道我们忽略输入的高字节以防它没有内联。或者使用 clang,编译器要求寄存器 arg 进行零扩展,并使用带有 LEA 的复制加法来设置高字节(而不是在 arg 是 int 时将高字节本身归零,我们将其转换为窄型)。 GCC 奇怪地使用or ah, 14,而不是更短的mov ah, 14godbolt.org/z/n1xDB7。我认为两者都会导致 AH 在 P6/SnB 上被单独重命名...
  • @PeterCordes :将字符作为整数传递给控制台输入和输出(以及文件流)是可以追溯到 K&R 的古老传统。由于getchar 将 EOF 返回为 8 位范围之外的负值,因此它们似乎标准化了 int 为所有相关函数传递的情况。 C 库今天仍在使用。
猜你喜欢
  • 2016-10-28
  • 1970-01-01
  • 2017-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-30
  • 1970-01-01
  • 2013-03-19
相关资源
最近更新 更多