是否可以使用Unicode“argv”?

时间:2009-11-03 00:00:23

标签: c unicode command-line-arguments

我正在为一个使用文件作为参数的应用程序编写一个小包装器。

包装器必须是Unicode,所以我使用wchar_t作为我拥有的字符和字符串。现在我发现自己遇到了问题,我需要在wchar_t和wchar_t字符串数组中包含程序的参数。

有可能吗?我将main函数定义为

int main(int argc, char *argv[])

我应该对argv使用wchar_t吗?

非常感谢,我似乎没有找到有关如何在C中正确使用Unicode的有用信息。

6 个答案:

答案 0 :(得分:11)

一般来说,没有。它取决于O / S,但C标准说'main()'的参数必须是'main(int argc,char ** argv)'或等价,所以除非char和wchar_t是相同的基本类型,你不能这样做。

话虽如此,你可以在程序中获得UTF-8参数字符串,将它们转换为UTF-16或UTF-32,然后继续生活。

在Mac(10.5.8,Leopard)上,我得到了:

Osiris JL: echo "ï€" | odx
0x0000: C3 AF E2 82 AC 0A                                 ......
0x0006:
Osiris JL: 

这是所有UTF-8编码的。 (odx是一个十六进制转储程序)。

另请参阅:Why is it that UTF-8 encoding is used when interacting with a UNIX/Linux environment

答案 1 :(得分:10)

便携式代码不支持它。 Windows(例如)支持使用wmain而不是main,在这种情况下,argv作为宽字符传递。

答案 2 :(得分:6)

在Windows上,您可以使用GetCommandLineW()CommandLineToArgvW()生成argv样式的wchar_t[]数组,即使该应用程序未针对Unicode进行编译。

答案 3 :(得分:3)

在Windows上,您可以使用wmain()进行UNICODE构建。虽然不便携。如果GCC或Unix / Linux平台提供类似的东西,我不知道。

答案 4 :(得分:3)

假设你的Linux环境使用UTF-8编码,那么下面的代码将准备你的程序,以便在C ++中轻松进行Unicode处理:

    int main(int argc, char * argv[]) {
      std::setlocale(LC_CTYPE, "");
      // ...
    }

接下来,wchar_t类型在Linux中是32位,这意味着它可以保存单独的Unicode代码点,并且您可以安全地使用wstring类型进行C ++中的经典字符串处理(逐个字符)。使用上面的setlocale调用,插入wcout将自动将输出转换为UTF-8,从wcin中提取将自动将UTF-8输入转换为UTF-32(1个字符= 1个代码点)。唯一的问题是argv [i]字符串仍然是UTF-8编码。

您可以使用以下函数将UTF-8解码为UTF-32。如果输入字符串已损坏,它将返回正确转换的字符,直到UTF-8规则被破坏的位置。如果您需要更多错误报告,可以改进它。但对于argv数据,可以安全地假设它是正确的UTF-8:

#define ARR_LEN(x) (sizeof(x)/sizeof(x[0]))

    wstring Convert(const char * s) {
        typedef unsigned char byte;
        struct Level { 
            byte Head, Data, Null; 
            Level(byte h, byte d) {
                Head = h; // the head shifted to the right
                Data = d; // number of data bits
                Null = h << d; // encoded byte with zero data bits
            }
            bool encoded(byte b) { return b>>Data == Head; }
        }; // struct Level
        Level lev[] = { 
            Level(2, 6),
            Level(6, 5), 
            Level(14, 4), 
            Level(30, 3), 
            Level(62, 2), 
            Level(126, 1)
        };

        wchar_t wc = 0;
        const char * p = s;
        wstring result;
        while (*p != 0) {
            byte b = *p++;
            if (b>>7 == 0) { // deal with ASCII
                wc = b;
                result.push_back(wc);
                continue;
            } // ASCII
            bool found = false;
            for (int i = 1; i < ARR_LEN(lev); ++i) {
                if (lev[i].encoded(b)) {
                    wc = b ^ lev[i].Null; // remove the head
                    wc <<= lev[0].Data * i;
                    for (int j = i; j > 0; --j) { // trailing bytes
                        if (*p == 0) return result; // unexpected
                        b = *p++;   
                        if (!lev[0].encoded(b)) // encoding corrupted
                            return result;
                        wchar_t tmp = b ^ lev[0].Null;
                        wc |= tmp << lev[0].Data*(j-1);
                    } // trailing bytes
                    result.push_back(wc);
                    found = true;
                    break;
                } // lev[i]
            }   // for lev
            if (!found) return result; // encoding incorrect
        }   // while
        return result;
    }   // wstring Convert

答案 5 :(得分:2)

在Windows上,您可以使用tchar.h和_tmain,如果在编译时定义了_UNICODE符号,则将其转换为wmain,否则为main。如果定义了unicode,TCHAR * argv []将同样扩展为WCHAR * argv [],否则将扩展为char * argv []。

如果您希望主要方法跨平台工作,可以将自己的宏定义为相同的效果。

TCHAR.h包含许多用于在wchar和char之间进行转换的便利宏。