接受非ASCII字符

时间:2015-06-14 18:04:13

标签: c windows argv non-ascii-characters

考虑这个程序:

#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

3 个答案:

答案 0 :(得分:4)

最简单的方法是使用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 repo

#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;
}

答案 1 :(得分:1)

由于您正在使用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),后跟Unicode代码点U+0300 (COMBINING GRAVE ACCENT)的表示。如果我改为使用

example -o àlf

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

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

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

对于只是字符串的参数,您可能希望使用NormalizeString函数查看规范化。其中链接的文档和示例应该可以帮助您了解该功能的工作原理。 Unicode中的规范化和其他一些事情可能是一段漫长的旅程,但如果这种事情让您感到兴奋,那么这也是一段有趣的旅程。

答案 2 :(得分:-1)

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

#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终端)时,我也会遇到这种情况。

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

我不知道Windows / MinGW的确切步骤,但简而言之,更改字符编码应解决您的问题