2009-11-03 64 views
11

我正在为使用文件作为参数的应用程序编写一个小包装。是否可以使用Unicode“argv”?

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

可能吗?我定义main功能

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

我应该使用wchar_t的对argv

非常感谢你,我似乎无法找到如何反正使用Unicode正确的C.

回答

9

一般来说,没有。它将取决于O/S,但是C标准认为'main()'的参数必须是'main(int argc,char ** argv)'或等价的,所以除非char和wchar_t是相同的基本类型,你不能这样做。话虽如此,你可以在程序中获得UTF-8参数字符串,将它们转换为UTF-16或UTF-32,然后继续生活。

在Mac(10.5.8,豹),我得到:

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

3

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

9

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

2

在Windows上,你可以使用TCHAR.H和_tmain,这将变成wmain如果_UNICODE符号在编译时定义,或以其他方式为主。如果定义了unicode,则TCHAR * argv []将类似地扩展为WCHAR * argv [];如果不是,则将char * argv []扩展为。

如果你想让你的主要方法跨平台工作,你可以定义自己的宏来达到同样的效果。

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

3

假设你的Linux环境使用UTF-8编码然后将以下代码将准备程序,方便的Unicode治疗在C++:

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 
6

在Windows上,你可以使用GetCommandLineW()CommandLineToArgvW()产生的argv的风格wchar_t[]阵列,即使应用程序未编译的Unicode 。