为 C 打印扩展 ASCII 字符的好方法是什么?

What are good methods in printing Extended ASCII characters for C?

首先我想看看 C 中的 ASCII 可打印字符是什么样的。

以下是我的代码:

#include <stdio.h>
int main(void)
{
    for (char a = 32; a < 127; a++)
        printf("a=%c\n", a); 
    return 0;
}

#include <stdio.h>
int main(void)
{
    for (unsigned char a = 32; a < 127; a++)
        printf("a=%c\n", a); 
    return 0;
}

以上两个代码片段工作得很好,告诉我有关 ASCII 可打印字符的信息。

接下来我想看看 C 的扩展 ASCII 字符。

#include <stdio.h>
int main(void)
{
    for (unsigned char a = 128; a < 256; a++)
        printf("a=%c\n", a); 

    return 0;
}

然后是死循环,里面有未知的奇怪字符

我哪里做错了?

我以为循环会在 a 达到 256 时停止,但它没有。

奇怪的字符是从哪里来的?

如何为 C 打印扩展 ASCII 字符?

循环

for (unsigned char a = 128; a < 256; a++)

在您的平台上永远运行,因为 255 + 1 是 0,因为 wrap around unsigned 类型。您可以使用混淆(当您第一次看到它时)

for (unsigned char a = 128; a >= 128; a++)

控制台打印的内容取决于系统使用的编码可能 ASCII),以及终端的打印方式该范围内的字符。

这个

a < 256

始终是 true,因为 unsigned char 有效范围是 <0, 255>。

你有一个无限循环,因为 unsigned char 可表示的最大值是 2551,并且将其递增超过该点会导致它回绕到零,所以条件 a < 256 始终为真。如果您改用 int,您的程序将按预期运行:

#include <stdio.h>
int main(void)
{
    for (int a = 128; a < 256; a++)
        printf("a=%c\n", a); 
    return 0;
}

int 传递给 printf 的 %c,2 完全没问题,只要它的 valueunsigned char 可表示的范围内。

但是,如果您 运行 在现代计算机上运行此程序,您仍然有可能获得 "strange characters"。例如,当我在我的电脑上 运行 它时,我得到 128 行

a=�

这是因为 现代 计算机的 CLI windows 需要 UTF-8 编码的 Unicode 文本,而在 UTF-8 中,U+007F 以上的所有字符都是使用多个字节编码。因此,终端仿真器每行接收到它认为是无效的、不完整的字节序列,并为它们打印一个特殊的 "replacement character"。在 U+0080..U+00FF 范围内查看 actual 字符的最简单方法是使用 C 的 "wide characters":

#include <wchar.h>
#include <locale.h>
int main(void)
{
    setlocale(LC_ALL, "");
    for (int a = 128; a < 256; a++)
        wprintf(L"U+%04X = '%lc'\n", a, (wchar_t)a);
    return 0;
}

wprintf 负责将宽字符转换为环境期望的任何文本编码。这不能保证有效,因为 C 的 "wide characters" 未指定且设计不当,以至于我实际上建议人们 不要 在生产代码中使用它们(相反,专门使用包含 UTF-8 的窄字符串),但是对于像这样的测试程序,您通常可以摆脱它。我得到这样的输出:

U+0080 = ''
U+0081 = ''
U+0082 = ''
...
U+00A0 = ' '
U+00A1 = '¡'
U+00A2 = '¢'
...
U+00FD = 'ý'
U+00FE = 'þ'
U+00FF = 'ÿ'

如果您的计算机不够现代,您可以获得不同的东西。 U+0080..U+009F 范围是更多无用的控制字符,这就是为什么它们不显示任何内容的原因。


1 技术上 [0, 255] 是 最小 所需范围 unsigned char; C 标准允许它可以表示更大范围的可能性,例如[0, 511]。如果您的程序 运行 位于 unsigned char 具有该范围的计算机上,它就可以工作。然而,多年来没有人制造过这样的计算机。如果你真的想担心它,包括 <limits.h> 并验证 CHAR_BIT 是 8 and/or UCHAR_MAX 是 255.

2 从技术上讲,由于 C 的一个残留特性称为 "default argument promotion",你 总是 传递一个 int%c,即使您提供的变量具有字符类型。