2009-11-03 3 views
11

Я пишу небольшую оболочку для приложения, которое использует файлы в качестве аргументов.Можно ли использовать Unicode «argv»?

Обертка должна быть в Юникоде, поэтому я использую wchar_t для символов и строк, которые у меня есть. Теперь у меня проблема, мне нужно иметь аргументы программы в массиве wchar_t и в строке wchar_t.

Возможно ли это? Я определения функции main как

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

Должен ли я использовать wchar_t для argv?

Спасибо большое, я, кажется, не найти полезную информацию о том, как использовать Unicode должным образом в С.

ответ

9

В общем, нет. Он будет зависеть от 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

3

В Windows в любом случае, вы можете иметь wmain() для UNICODE строит. Не портативный, хотя. Я не знаю, если GCC или Unix/Linux-платформы предоставляют что-то подобное.

9

Портативный код не поддерживает его. Windows (например) поддерживает использование wmain вместо main, и в этом случае argv передается как широкие символы.

2

В Windows, вы можете использовать tchar.h и _tmain, который будет превращен в wmain если символ _UNICODE определяется во время компиляции, или основной иначе. TCHAR * argv [] также будет расширен до WCHAR * argv [], если unicode определен, и char * argv [], если нет.

Если вы хотите, чтобы ваш основной метод работал с кросс-платформой, вы можете определить свои собственные макросы с тем же эффектом.

TCHAR.h содержит ряд удобных макросов для преобразования между wchar и char.

3

Предполагая, что среда Linux использует кодировку UTF-8, то следующий код будет подготовить программу для легкой обработки Unicode в C++:

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

Далее wchar_t тип 32-бит в Linux, что означает его может содержать отдельные кодовые точки 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 ,

Смежные вопросы