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

包装器需要采用 Unicode,因此我使用 wchar_t 来表示我拥有的字符和字符串。现在我发现自己遇到了问题,我需要将程序的参数放在 wchar_t 数组和 wchar_t 字符串中。

是否可以?我正在定义 main 充当

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

我应该使用 wchar_t 吗 argv?

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

有帮助吗?

解决方案

一般来说,没有。这取决于操作系统,但 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 是一个十六进制转储程序)。

也可以看看: 为什么与UNIX/Linux环境交互时使用UTF-8编码

其他提示

可移植代码不支持它。Windows(例如)支持使用 wmain 代替 main, ,在这种情况下 argv 作为宽字符传递。

在 Windows 上,您可以使用 GetCommandLineW()CommandLineToArgvW() 产生 argv 风格 wchar_t[] 数组,即使应用程序不是针对 Unicode 编译的。

无论如何,在 Windows 上,你可以有一个 wmain() 用于 UNICODE 构建。虽然不便携。我不知道 GCC 或 Unix/Linux 平台是否提供类似的东西。

假设您的 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

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

如果您想让您的 main 方法跨平台工作,您可以定义自己的宏来达到相同的效果。

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top