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

npo*_*avs 3 c windows unicode mingw

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


背景:

出现此问题所描述的问题是因为 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;
}
Run Code Online (Sandbox Code Playgroud)

测试编码

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

#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;
}
Run Code Online (Sandbox Code Playgroud)

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

C:\Users\npostavs\tmp>chcp
Active code page: 850
Run Code Online (Sandbox Code Playgroud)

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

C:\Users\npostavs\tmp>cmd-chars æÆ
230 198
Run Code Online (Sandbox Code Playgroud)

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

制作cmd-chars.exe带参数的快捷方式???(这些在代码页 1252 中不存在)给出

C:\Users\npostavs\tmp>shortcut-cmd-chars.lnk
97 223 63
Run Code Online (Sandbox Code Playgroud)

这是aß?.

小智 5

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

请注意,WideCharToMultiByte使用输出缓冲区大小(字节数)为 0 进行调用将允许您确定指定字符数所需的 UTF-8 字节数(或者如果您希望传递 -1,则包括空终止符在内的整个宽字符串)作为简化代码的宽字符数)。然后,您可以使用mallocet al分配所需的字节数。并WideCharToMultiByte使用正确的字节数而不是 0 再次调用。如果这对性能至关重要,那么不同的解决方案可能是最好的,但由于这是获取命令行参数的一次性函数,我会说任何减少在性能上可以忽略不计。

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

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