接受非ASCII字符

考虑这个程序:

#include <stdio.h> int main(int argc, char* argv[]) { printf("%s\n", argv[1]); return 0; } 

我这样编译它:

 x86_64-w64-mingw32-gcc -o alpha alpha.c 

问题是如果我给它一个非ASCII的参数:

 $ ./alpha róisín r is n 

我如何编写和/或编译这个程序,使其接受非ASCII字符

为了回应alk :不,程序打印错误。 看到这个例子:

 $ echo Ω | od -tx1c 0000000 ce a9 0a 316 251 \n 0000003 $ ./alpha Ω | od -tx1c 0000000 4f 0d 0a O \r \n 0000003 

最简单的方法是使用wmain

 #include <fcntl.h> #include <stdio.h> int wmain (int argc, wchar_t** argv) { _setmode(_fileno(stdout), _O_WTEXT); wprintf(L"%s\n", argv[1]); return 0; } 

它也可以用GetCommandLineW完成; 这里是在HandBrake回购中找到的代码的简单版本:

 #include <stdio.h> #include <windows.h> int get_argv_utf8(int* argc_ptr, char*** argv_ptr) { int argc; char** argv; wchar_t** argv_utf16 = CommandLineToArgvW(GetCommandLineW(), &argc); int i; int offset = (argc + 1) * sizeof(char*); int size = offset; for (i = 0; i < argc; i++) size += WideCharToMultiByte(CP_UTF8, 0, argv_utf16[i], -1, 0, 0, 0, 0); argv = malloc(size); for (i = 0; i < argc; i++) { argv[i] = (char*) argv + offset; offset += WideCharToMultiByte(CP_UTF8, 0, argv_utf16[i], -1, argv[i], size-offset, 0, 0); } *argc_ptr = argc; *argv_ptr = argv; return 0; } int main(int argc, char** argv) { get_argv_utf8(&argc, &argv); printf("%s\n", argv[1]); return 0; } 

由于您使用MinGW(实际上是MinGW-w64,但在这种情况下不应该),您可以访问Windows API,因此以下内容适用于您。 它可能会更干净,实际上测试正确,但它应该至少提供一个好主意:

 #define _WIN32_WINNT 0x0600 #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <wchar.h> #include <windows.h> int main (void) { int argc; int i; LPWSTR *argv; argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (argv == NULL) { FormatMessageA( ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS), NULL, GetLastError(), 0, (LPWSTR)&error, 0, NULL); fprintf(stderr, error); fprintf(stderr, "\n"); LocalFree(error); return EXIT_FAILURE; } for (i = 0; i < argc; ++i) wprintf(L"argv[%d]: %ls\n", i, argv[i]); // You must free argv using LocalFree! LocalFree(argv); return 0; } 

请记住这个问题:Windows不会为您编写字符串。 我用我自己的Windows键盘布局,使用组合字符(我很奇怪),所以当我键入

 example -o àlf 

在我的Windows命令提示符下,我得到以下输出:

 argv[0]: example argv[1]: -o argv[2]: a\u0300lf 

a\u0300U+0061 (LATIN SMALL LETTER A) a\u0300 U+0061 (LATIN SMALL LETTER A)然后是Unicode代码点U+0300 (COMBINING GRAVE ACCENT) 。 如果我反而使用

 example -o àlf 

它使用预U+00E0 (LATIN SMALL LETTER A WITH GRAVE)字符U+00E0 (LATIN SMALL LETTER A WITH GRAVE) ,输出会有所不同:

 argv[0]: example argv[1]: -o argv[2]: \u00E0lf 

其中\u00E0是由Unicode代码点U + 00E0表示的预\u00E0字符à表示形式。 然而,虽然我可能是一个奇怪的人做这个, 越南代码页1258实际上包括组合字符。 这通常不应该影响文件名处理,但可能会遇到一些困难。

对于只是字符串的参数,您可能希望查看NormalizeString函数的NormalizeString 。 链接的文档和示例应该可以帮助你理解函数是如何工作的。 Unicode中的规范化和其他一些事情可能是一个漫长的旅程,但如果这种事情激发你,这也是一个有趣的旅程。

尝试编译并运行以下程序:

 #include <stdio.h> int main() { int i = 0; for( i=0; i<256; i++){ printf("\nASCII Character #%d:%c ", i, i); } printf("\n"); return 0; } 

在你的输出中,你应该看到128号以后的小问号。 仅供参考我正在使用Ubuntu,当我编译和运行这个程序(GNOME终端),这也发生在我身上。

但是,如果我去终端>设置字符编码…并选择西方(WINDOWS-1252)而不是Unicode(UTF-8),并重新运行程序,扩展的ASCII字符显示正确。

我不知道Windows / MinGW的确切步骤 ,但总之, 更改字符编码应该可以解决您的问题