为什么每当我尝试从 txt 文件中读取不可打印的字符时,C 中的 fgetc() 总是读取额外的、不存在的字符?
Why does fgetc() in C always reads extra, non-existent characters whenever I try to read non-printable characters from txt files?
我正在尝试从文本文件中读取不可打印的字符,打印出字符的 ASCII 码,最后将这些不可打印的字符写入输出文件。
但是,我发现每读一个非打印字符,总有一个额外的非打印字符存在于我真正想读的内容前面。
比如我要读的字符是“§”。
当我在我的程序中打印出它的 ASCII 码时,它不是只打印“167”,而是打印出“194 167”。
我在调试器中查找并在字符数组中看到“§”。但是我的输入文件中没有任何地方。
screenshot of debugger
在我将不可打印字符写入输出文件后,我注意到它也只是“§”,而不是“§”。
我读到的每一个不可打印的字符都附加了一个额外的字符。为什么会这样?我该如何摆脱它?
谢谢!
代码如下:
case 1:
mode = 1;
FILE *fp;
fp = fopen ("input2.txt", "r");
int charCount = 0;
while(!feof(fp)) {
original_message[charCount] = fgetc(fp);
charCount++;
}
original_message[charCount - 1] = '[=10=]';
fclose(fp);
k = strlen(original_message);//split the original message into k input symbols
printf("k: \n%lld\n", k);
printf("ASCII code:\n");
for (int i = 0; i < k; i++)
{
ASCII = original_message[i];
printf("%d ", ASCII);
}
C 的 getchar
(以及 getc
和 fgetc
)函数旨在读取单个字节。它们不会直接处理“宽”或“多字节”字符,例如出现在 Unicode 的 UTF-8 编码中的字符。
但是还有其他函数是专门设计用于处理那些扩展字符的。特别是,如果您愿意,可以将对 fgetc(fp)
的调用替换为 fgetwc(fp)
,然后您应该能够开始阅读像 §
这样的字符本身。
您必须 #include <wchar.h>
才能获得 fgetwc
的原型。你可能需要添加调用
setlocale(LC_CTYPE, "");
在您的程序的顶部使您的程序的字符集“语言环境”与操作系统的字符集同步。
不是你的原始代码,但我写了这个小程序:
#include <stdio.h>
#include <wchar.h>
#include <locale.h>
int main()
{
wchar_t c;
setlocale(LC_CTYPE, "");
while((c = fgetwc(stdin)) != EOF)
printf("%lc %d\n", c, c);
}
当我输入“A”时,它会打印 A 65
。
当我键入“§”时,它会打印 § 167
。
当我键入“Ƶ”时,它会打印 Ƶ 437
。
当我输入“†”时,它会打印 † 8224
.
现在,综上所述,使用 fgetwc
等函数读取宽字符并不是处理扩展字符的唯一方法,甚至不一定是最好的方法。在您的情况下,它会带来一些额外的后果:
- 您的
original_message
数组必须是 wchar_t
的数组,而不是 char
. 的数组
- 您的
original_message
数组不会是普通的 C 字符串 — 它是“宽字符串”。所以你不能在上面调用 strlen
;你将不得不打电话给 wcslen
.
- 同样,您不能使用
%s
打印它,也不能使用 %c
打印它的字符。您必须记住使用 %ls
或 %lc
.
因此,尽管您可以 将整个程序转换为在各处使用“宽”字符串和“w
”函数,但这是一项繁重的工作。在许多情况下,尽管存在像您询问的异常现象,但使用 UTF-8 everywhere 更容易,因为它倾向于 Just Work。特别是,只要您不必将字符串分开并使用其各个字符,或使用 strlen
计算字符串的 on-screen 显示长度(以“字符”为单位),您可以到处都使用纯 C 字符串,让 UTF-8 序列的魔力处理用户碰巧输入的任何 non-ASCII 个字符。
我正在尝试从文本文件中读取不可打印的字符,打印出字符的 ASCII 码,最后将这些不可打印的字符写入输出文件。
但是,我发现每读一个非打印字符,总有一个额外的非打印字符存在于我真正想读的内容前面。
比如我要读的字符是“§”。 当我在我的程序中打印出它的 ASCII 码时,它不是只打印“167”,而是打印出“194 167”。
我在调试器中查找并在字符数组中看到“§”。但是我的输入文件中没有任何地方。 screenshot of debugger
在我将不可打印字符写入输出文件后,我注意到它也只是“§”,而不是“§”。
我读到的每一个不可打印的字符都附加了一个额外的字符。为什么会这样?我该如何摆脱它?
谢谢!
代码如下:
case 1:
mode = 1;
FILE *fp;
fp = fopen ("input2.txt", "r");
int charCount = 0;
while(!feof(fp)) {
original_message[charCount] = fgetc(fp);
charCount++;
}
original_message[charCount - 1] = '[=10=]';
fclose(fp);
k = strlen(original_message);//split the original message into k input symbols
printf("k: \n%lld\n", k);
printf("ASCII code:\n");
for (int i = 0; i < k; i++)
{
ASCII = original_message[i];
printf("%d ", ASCII);
}
C 的 getchar
(以及 getc
和 fgetc
)函数旨在读取单个字节。它们不会直接处理“宽”或“多字节”字符,例如出现在 Unicode 的 UTF-8 编码中的字符。
但是还有其他函数是专门设计用于处理那些扩展字符的。特别是,如果您愿意,可以将对 fgetc(fp)
的调用替换为 fgetwc(fp)
,然后您应该能够开始阅读像 §
这样的字符本身。
您必须 #include <wchar.h>
才能获得 fgetwc
的原型。你可能需要添加调用
setlocale(LC_CTYPE, "");
在您的程序的顶部使您的程序的字符集“语言环境”与操作系统的字符集同步。
不是你的原始代码,但我写了这个小程序:
#include <stdio.h>
#include <wchar.h>
#include <locale.h>
int main()
{
wchar_t c;
setlocale(LC_CTYPE, "");
while((c = fgetwc(stdin)) != EOF)
printf("%lc %d\n", c, c);
}
当我输入“A”时,它会打印 A 65
。
当我键入“§”时,它会打印 § 167
。
当我键入“Ƶ”时,它会打印 Ƶ 437
。
当我输入“†”时,它会打印 † 8224
.
现在,综上所述,使用 fgetwc
等函数读取宽字符并不是处理扩展字符的唯一方法,甚至不一定是最好的方法。在您的情况下,它会带来一些额外的后果:
- 您的
original_message
数组必须是wchar_t
的数组,而不是char
. 的数组
- 您的
original_message
数组不会是普通的 C 字符串 — 它是“宽字符串”。所以你不能在上面调用strlen
;你将不得不打电话给wcslen
. - 同样,您不能使用
%s
打印它,也不能使用%c
打印它的字符。您必须记住使用%ls
或%lc
.
因此,尽管您可以 将整个程序转换为在各处使用“宽”字符串和“w
”函数,但这是一项繁重的工作。在许多情况下,尽管存在像您询问的异常现象,但使用 UTF-8 everywhere 更容易,因为它倾向于 Just Work。特别是,只要您不必将字符串分开并使用其各个字符,或使用 strlen
计算字符串的 on-screen 显示长度(以“字符”为单位),您可以到处都使用纯 C 字符串,让 UTF-8 序列的魔力处理用户碰巧输入的任何 non-ASCII 个字符。