2009-11-03 5 views
11

Piszę małe opakowanie dla aplikacji, która używa plików jako argumentów.Czy można użyć "argv" w standardzie Unicode?

Opakowanie musi być w formacie Unicode, więc używam wchar_t dla znaków i ciągi mam. Teraz znajduję się w problemie, potrzebuję mieć argumenty programu w tablicy wchar_t i w wchar_t napisie.

Czy to możliwe? Ja definiując funkcję main jako

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

powinienem użyć wchar_t za argv?

Dziękuję bardzo, nie wydaje się znaleźć przydatne informacje na temat korzystania z Unicode poprawnie w C

Odpowiedz

9

Na ogół nie. Będzie zależeć od O/S, ale standard C mówi, że argumenty "main()" muszą być "główne (int argc, char ** argv)" lub równoważne, więc jeśli char i wchar_t są tym samym podstawowym typem , nie możesz tego zrobić.

Mimo, że można dostać ciągi UTF-8 argumentów do programu, konwertować je do UTF-16 lub UTF-32, a następnie zabrać się za życia.

Na komputerze Mac (10.5.8 Leopard), mam:

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

To wszystko kodowanie UTF-8. (odx to program zrzutu heksadecymalnego).

Zobacz także: Why is it that UTF-8 encoding is used when interacting with a UNIX/Linux environment

3

W Windows tak, można mieć wmain() dla UNICODE buduje. Nie przenośne. Nie wiem, czy platformy GCC lub Unix/Linux zapewniają coś podobnego.

9

Portable kod nie obsługuje. Windows (na przykład) obsługuje używanie wmain zamiast main, w którym to przypadku argv jest przekazywane jako szerokie znaki.

2

W systemie Windows można użyć tchar.h i _tmain, który zostanie przekształcony wmain jeśli symbol _UNICODE jest określona w czasie kompilacji, lub głównym inaczej. TCHAR * argv [] będzie podobnie rozszerzony na WCHAR * argv [], jeśli zdefiniowany jest kod Unicode, i char * argv [], jeśli nie.

Jeśli chcesz mieć swoją główną platformę krzyżowego praca metodą, można zdefiniować własne makra do tego samego skutku.

TCHAR.h zawiera szereg makr wygoda dla konwersji między WCHAR i char.

3

Zakładając, że środowisko Linux używa kodowania UTF-8, a następnie następujący kod przygotuje program do łatwego leczenia Unicode w C++:

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

Następnie wchar_t typ jest 32-bitowy w systemie Linux, co oznacza, że może przechowywać poszczególne punkty kodowe Unicode i bezpiecznie używać typu Wstring do klasycznego przetwarzania ciągów w C++ (znak po znaku). W powyższym wywołaniu setlocale, wstawienie do wcout automatycznie przetłumaczy twoje wyjście na UTF-8, a wyodrębnienie z wcin automatycznie przetłumaczy wejście UTF-8 na UTF-32 (1 znak = 1 punkt kodowy). Jedynym problemem, który pozostaje, jest to, że ciągi argv [i] są nadal kodowane w UTF-8.

Możesz użyć następującej funkcji do dekodowania UTF-8 do UTF-32.Jeśli ciąg wejściowy jest uszkodzony, zwróci poprawnie skonwertowane znaki, aż do miejsca, w którym złamano reguły UTF-8. Możesz go poprawić, jeśli potrzebujesz więcej raportów o błędach. Ale dla danych argv można bezpiecznie założyć, że jest ona poprawna 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

W systemie Windows można użyć GetCommandLineW() i CommandLineToArgvW() do wytworzenia argv-stylem wchar_t[] tablicę, nawet jeśli aplikacja nie jest skompilowany dla Unicode .