2015-06-21 173 views
1

考虑下面的程序:FWRITE非ASCII字符

#include <stdio.h> 
#include <string.h> 

int main() { 
    char* alpha = "Ω"; 
    fwrite(alpha, 1, strlen(alpha), stdout); 
    return 0; 
} 

在Windows上,我得到以下的输出:

�� 

我试图改变行这样:

char* alpha = "zΩ"; 

并正确打印。输出正确编码,就无法正确打印 :

 
$ bad | od -tx1c 
0000000 ce a9 
     316 251 

$ good | od -tx1c 
0000000 7a ce a9 
      z 316 251 

我如何FWRITE用非ASCII作为第一个字符?

为了回应一些评论:源文件被正确格式化为UTF-8,和我的代码页也被正确设置为UTF-8:

 
$ chcp.com 
Active code page: 65001 
+1

呼叫'_setmode(_fileno(标准输出),_O_U16TEXT)'然后写一个'wchar_t的*'广字符串使用'fwrite'。由于底层CRT文件是UTF-16模式并且是控制台,因此通过调用Unicode API'WriteConsoleW'实现写入。 – eryksun

+1

这适用于我:'wchar_t * alpha = L“Ω”;''_setmode(_fileno(stdout),_O_U16TEXT);''fwrite(alpha,2,wcslen(alpha),stdout);' – eryksun

+0

{0xa9,0x03 }是“Ω”的小端UTF-16,即U + 03A9。你是否使用普通的Windows控制台来运行这个控制台,或者在一个POSIX shell中运行,并将其导入到某种pty实现中?检查'GetFileType(GetStdHandle(STD_OUTPUT_HANDLE))'。它是'FILE_TYPE_CHAR'(2,一个控制台缓冲区句柄)还是'FILE_TYPE_PIPE'(3)? – eryksun

回答

1

在Windows fwrite电话WriteFile内部,在这案件不正确。我 的解决办法是只需要调用WriteFile直接:

#include <windows.h> 

int main() { 
    char* alpha = "Ω"; 
    DWORD bravo; 
    WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), alpha, strlen(alpha), &bravo, 0); 
    return 0; 
} 
+1

一般来说,你需要'lpNumberOfBytesWritten'。如果stdout是管道呢?例如,“如果写入缓冲区空间不足的非阻塞字节模式管道句柄,WriteFile将返回带有* lpNumberOfBytesWritten eryksun

+1

如果您仍然需要单独的控制台代码路径,您最好自己将UTF-8解码为UTF-16并调用WriteConsoleW。当stdout不是控制台时,你可以使用'fwrite'。 – eryksun

+1

我必须强调控制台中的代码页65001已损坏。尝试将非ASCII的Unicode粘贴到控制台中,并尝试通过“ReadFile”读取它。它使用'WideCharToMultiByte'使用大小为ANSI的临时缓冲区编码到控制台代码页,即每个'wchar_t'字符1个字节。对于给定非ASCII字符的UTF-8,这将失败。但conhost.exe不通过调整临时缓冲区来处理这个问题。它只是忽略失败并返回它'成功'读取0个字节。你无能为力。即使Windows 10仍然有这个错误。 – eryksun