为 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 完全没问题,只要它的 value 在 unsigned 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
,即使您提供的变量具有字符类型。
首先我想看看 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 完全没问题,只要它的 value 在 unsigned 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
,即使您提供的变量具有字符类型。