在单个C代码中使用printf和wprintf

27

使用printfwprintf函数在代码中一起使用时出现问题。如果先打印常规字符串,那么wprintf就不能工作。如果先使用wprintf,则printf就不能工作。

#include <stdio.h>
#include <wchar.h>
#include <stdlib.h>
#include <locale.h>

int main() 
{
    setlocale(LC_ALL,"");

    printf("No printing!\n");
    wprintf(L"Printing!\n");
    wprintf(L"Wide char\n");
    printf("ASCII\n");
    return 0;
}

输出:

No printing!
ASCII
< p > 当 < /p >
#include <stdio.h>
#include <wchar.h>
#include <stdlib.h>
#include <locale.h>

int main() 
{
    setlocale(LC_ALL,"");

    wprintf(L"Printing!\n");
    printf("No printing!\n");
    wprintf(L"Wide char\n");
    printf("ASCII\n");
    return 0;
}

输出:

Printing!
Wide char

我正在使用gcc(GCC)4.6.1 20110819和glibc 2.14在64位Linux 3.0上。


Linux 3.0?那是什么?哪个发行版? - bmargulies
@bmargulies:内核版本。发行版是Archlinux。 - Hubert Kario
2个回答

24

这是可以预料的;你的代码正在调用未定义的行为。根据C标准,每个FILE流都有一个相关联的“方向”(即“字节”或“宽字符”),该方向由对其执行的第一个操作设置,并且可以使用fwide函数进行检查。调用任何方向与流的方向冲突的函数会导致未定义的行为。


2
@alk 未定义行为意味着在这种情况下没有预期的行为。因此,输出空值是可以接受的,将文本静默转换为正确的方向或打印垃圾也是可以接受的。 - That Chuck Guy
@DRH:谢谢!“...应用程序的行为将变得奇怪或者应用程序会崩溃...”至少这个“或”让我倾向于理解事情似乎有些“未定义”...;-) - alk
1
@Hubert:这不是man页面中的一个bug。http://www.kernel.org/doc/man-pages/online/pages/man3/wprintf.3.html 上说:“stdout不应该是面向字节的”。 - Michael Burr
2
能否重新打开 stdout 并更改方向? - Matt Clarkson
1
"freopen" 可以清除方向,但它也有缺点。请参考 POSIX 中的相关内容:http://pubs.opengroup.org/onlinepubs/9699919799/functions/freopen.html 特别是 "应用使用" 部分。 - R.. GitHub STOP HELPING ICE
显示剩余4条评论

5

补充R..已经接受的答案:

虽然很少这样做,但检查printf/wprintf的返回代码会更清楚地表明它们中的一个不起作用(根据流的当前方向,它应该为打印函数返回-1无效)。

不幸的是,检查标准库函数中的错误的常见模式:

if (wprintf(...) == -1) { perror("wprintf"); ... }

在这里可能不会有太大的帮助:如果流被设置为输出非宽字符,而您调用了wprintferrno可能不会被设置,您将收到wprintf:Success,这并没有提供太多信息。

因此,当您不知道流的字符方向时,确实很难理解这个问题。


检查返回值有助于报告错误,而不是当您遇到未定义行为时。wprintf在方向错误时未指定失败。相反,当方向错误时它的行为根本没有被指定。这就是未定义的含义。 - R.. GitHub STOP HELPING ICE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接