如何在mingw中检测命令行参数的字符编码

时间:2014-07-31 22:54:52

标签: c windows unicode mingw

假设它们是ISO-8859-15(Window-1252?)是安全的,还是有一些我可以调用来查询它的函数?最终目标是转换为UTF-8。


背景

this question描述的问题产生,因为XMLStarlet假定其命令行参数是UTF-8。在Windows下,似乎它们实际上是ISO-8859-15(Window-1252?),或者至少在main的开头添加以下内容使得工作正常:

char **utf8argv = malloc(sizeof(char*) * (argc+1));
utf8argv[argc] = NULL;

{
    iconv_t windows2utf8 = iconv_open("UTF-8", "ISO-8859-15");
    int i;
    for (i = 0; i < argc; i++) {
        const char *arg = argv[i];
        size_t len = strlen(arg);
        size_t outlen = len*2 + 1;
        char *utfarg = malloc(outlen);

        char *out = utfarg;
        size_t ret = iconv(windows2utf8,
            &arg, &len,
            &out, &outlen);

        if (ret < 0) {
            perror("iconv");
            utf8argv[i] = NULL;
            continue;
        }

        out[0] = '\0';
        utf8argv[i] = utfarg;
    }

    argv = utf8argv;
}

测试编码

以下程序以十进制打印出第一个参数的字节:

#include <strings.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
    for (int i = 0; i < strlen(argv[1]); i++) {
        printf("%d ", (unsigned char) argv[1][i]);
    }
    printf("\n");
    return 0;
}

chcp报告代码页850,因此字符æ和Æ应分别为145和146.

C:\Users\npostavs\tmp>chcp
Active code page: 850

但我们看到230和198报告哪些匹配1252

C:\Users\npostavs\tmp>cmd-chars æÆ
230 198

在代码页之外传递字符会导致有损转换

使用参数cmd-chars.exe创建αβγ的快捷方式(代码页1252中不存在这些快捷方式)

C:\Users\npostavs\tmp>shortcut-cmd-chars.lnk
97 223 63

哪个是aß?

3 个答案:

答案 0 :(得分:4)

您可以通过调用CommandLineToArgvW作为第一个参数调用GetCommandLineW来获取argv样式的宽字符串数组中的命令行参数。这是唯一的便携式Windows方式,尤其是代码页混乱;例如,日语字符可以通过Windows快捷方式传递。之后,您可以使用WideCharToMultiByte代码页参数CP_UTF8将每个宽字符argv元素转换为UTF-8。

请注意,调用WideCharToMultiByte并输出缓冲区大小(字节数)为0将允许您确定指定字符数所需的UTF-8字节数(或包含null的整个宽字符串)终结符,如果你希望传递-1作为宽字符的数量,以简化你的代码)。然后,您可以使用malloc等分配所需的字节数。并使用正确的字节数而不是0再次调用WideCharToMultiByte。如果这是性能关键的,那么另一种解决方案可能是最好的,但由于这是获取命令行参数的一次性函数,我们说任何性能下降都可以忽略不计。

当然,不要忘记释放所有内存,包括使用LocalFree返回的指针作为参数调用CommandLineToArgvW

有关这些功能以及如何使用它们的更多信息,请单击链接以查看MSDN文档。

答案 1 :(得分:2)

命令行参数位于系统默认代码页中,具体取决于系统设置。根本不是指定特定的源字符集,而是指定"char""",让iconv_open()找出系统字符集的实际内容:

iconv_t windows2utf8 = iconv_open("UTF-8", "char");

否则,您最好将命令行检索为UTF-16而不是Ansi,然后您可以使用iconv_open("UTF-8", "UTF-16LE")直接将其转换为UTF-8,或者像Chrono建议的那样WideCharToMultiByte(CP_UTF8)

答案 2 :(得分:-2)

好像你在windows下。

在这种情况下,您可以进行system()调用以运行CHCP命令。

   #include <stdlib.h>     // Uses: system()
   #include <stdio.h> 
   // ..... 

   // 1st: Store the present windows codepage in a text file:
   system("CMD /C \"CHCP > myenc.txt\"");

   // 2nd: Read the first line in the file:
   FILE *F = fopen("myenc.txt", "r");      
   char buffer[100];
   fgets(buffer, F);
   fclose(F);

   // 3rd: Analyze the loaded string to find the Windows codepage:
   int codepage = my_CHCP_analizer_func(buffer);   

   // The function my_CHCP_analizer_func() must be written for you,
   // and it has to take in account the way in that CHCP prints the information.  

最后,可以检查CHCP发送的代码页,例如:

Windows Codepages