为什么每当我尝试从 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(以及 getcfgetc)函数旨在读取单个字节。它们不会直接处理“宽”或“多字节”字符,例如出现在 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 等函数读取宽字符并不是处理扩展字符的唯一方法,甚至不一定是最好的方法。在您的情况下,它会带来一些额外的后果:

  1. 您的 original_message 数组必须是 wchar_t 的数组,而不是 char.
  2. 的数组
  3. 您的 original_message 数组不会是普通的 C 字符串 — 它是“宽字符串”。所以你不能在上面调用 strlen;你将不得不打电话给 wcslen.
  4. 同样,您不能使用 %s 打印它,也不能使用 %c 打印它的字符。您必须记住使用 %ls%lc.

因此,尽管您可以 将整个程序转换为在各处使用“宽”字符串和“w”函数,但这是一项繁重的工作。在许多情况下,尽管存在像您询问的异常现象,但使用 UTF-8 everywhere 更容易,因为它倾向于 Just Work。特别是,只要您不必将字符串分开并使用其各个字符,或使用 strlen 计算字符串的 on-screen 显示长度(以“字符”为单位),您可以到处都使用纯 C 字符串,让 UTF-8 序列的魔力处理用户碰巧输入的任何 non-ASCII 个字符。