ANSI C:isprint()对非ASCII字符返回true?

时间:2012-01-25 17:29:41

标签: c unicode ascii non-ascii-characters ansi-c

我有一些C代码应该打印文件的全部内容。程序之前打印的文件很好,但是当它打印一秒钟时,我一直看到一个肯定不应该出现的Unicode字符。

int c = fgetc(file);
putchar((!isprint(c) ? : c));

(包裹在while(!feof(file))
应该只打印ASCII可打印字符,除非我弄错了。无论如何,它打印的第一件事是\357\277\275,它不是ASCII,并且不可打印。

该文件仅包含:foo+bar.foo+t-bar.foo+completely fake

并打印出这个:�foo+bar.foo+t-bar.foo+completely fake(在奇怪的角色与其余角色之间换行)。

只需打印全部(la putchar(c))就可以在行尾添加完全相同的字符。

我甚至尝试使用另一个文件(通过重命名旧文件并使用软链接到另一个文件),但我得到了完全相同的结果。

如果文件为空,它也会这样做。

该文件是完全纯文本,使用vim创建,并且没有任何特殊之处。

这是原始代码:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>

int main(void)
{
    char *headp = "../include/header";
    char *listp = "../.piclist";
    FILE *head, *list;

    puts("Content-Type: text/html; charset=utf-8\nExpires: 0\n");

    puts("<!DOCTYPE html>\n<html lang='en'>\n<head>");
    puts("\t<title>Foo</title>");
    puts("\t<link rel='stylesheet' href='/css/main.css' />");
    puts("\t<link rel='stylesheet' href='/css/foo.css' />");
    puts("</head>\n<body>");

    head = fopen(headp, "r");
    if (errno) {
            perror("cannot open include/header");
            errno = 0;
    } else {
            while (!feof(head)) putchar(fgetc(head));
            putchar('\n');
    fclose(head);
    }

    list = fopen(listp, "r");
    if (errno) perror("cannot open .piclist");
    else {
    while (!feof(list)) {
            while (!feof(list)) {
                    int c = fgetc(list);
                    putchar((!isprint(c) ? : c));
            }
    }
    fclose(list);
    } /* else */

    fputs("\n<footer>\n\t<hr />\n\t<p>Copyright 2011-2012 the ", stdout);
    fputs("<a href='mailto:foo@example.com'> ", stdout);
    fputs("Foo Bar of Baz</a> of ", stdout);
    fputs("<a href='http://blah.org'>Blah United ", stdout);
    fputs("</a></p>\n</footer>\n</body>\n</html>\n",stdout);

    return 0;
}

3 个答案:

答案 0 :(得分:2)

不要使用feof()(至少不是你使用它的方式)

另外,你对errno的使用是错误的。 errno only 在某些操作指示错误返回后包含可用值(通常为NULL,或-1作为返回值)

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>

int main(void)
{
    char *headp = "../include/header";
    char *listp = "../.piclist";
    FILE *head, *list;
    int ch;

    puts("Content-Type: text/html; charset=utf-8\nExpires: 0\n");

    puts("<!DOCTYPE html>\n<html lang='en'>\n<head>");
    puts("\t<title>Warrenton Latin School | Gallery</title>");
    puts("\t<link rel='stylesheet' href='/css/main.css' />");
    puts("\t<link rel='stylesheet' href='/css/gallery.css' />");
    puts("</head>\n<body>");

    head = fopen(headp, "r");
    if (!head) {
            perror("cannot open include/header");
            errno = 0;
    } else {
        while (1) {
            ch = fgetc(head);
            if (ch == EOF) break;
            putchar(ch);
            }
        putchar('\n');
        fclose(head);
    }

    list = fopen(listp, "r");
    if (!list) perror("cannot open .piclist");
    else while (1) {
        ch = fgetc(list);
        if (ch == EOF) break;
        putchar((!isprint(c) ? : c));
    }
    fclose(list);

    fputs("\n<footer>\n\t<hr />\n\t<p>Copyright 2011-2012 the ", stdout);
    fputs("<a href='mailto:warrentonlatinschool@gmail.com'> ", stdout);
    fputs("Warrenton Latin School</a> co-op of ", stdout);
    fputs("<a href='http://warrentonumc.org'>Warrenton United ", stdout);
    fputs("Methodist Church</a></p>\n</footer>\n</body>\n</html>\n",stdout);

    return 0;
}

答案 1 :(得分:1)

忽略代码中可能出现的错误isprint()会将所有字符都视为可打印的,0x00 - 0x1f0x7f除外。

UTF BOM和7位ANSI之外的其他字符仍然可以打印(尽管它们的含义可能会因编码而改变)。

答案 2 :(得分:0)

当您离开第二个运算符?:empty时,它等于条件的结果。对于不可打印的字符,isprintc(c)返回0,因此trenary运算符的条件部分是!0,等于1.因此putchar尝试打印无效的ASCII字符并中断。