2009-11-03 34 views
11

Tôi đang viết một trình bao bọc nhỏ cho một ứng dụng sử dụng các tệp làm đối số.Có thể sử dụng Unicode "argv" không?

Trình bao bọc cần phải ở dạng Unicode, vì vậy tôi đang sử dụng wchar_t cho các ký tự và chuỗi mà tôi có. Bây giờ tôi thấy mình trong một vấn đề, tôi cần phải có các đối số của chương trình trong một mảng của wchar_t và trong một chuỗi wchar_t.

Có thể không? Tôi đang định chức năng main như

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

Tôi có nên sử dụng của wchar_t cho argv?

Cảm ơn bạn rất nhiều, tôi không có vẻ để tìm thông tin hữu ích về cách sử dụng Unicode đúng trong C.

Trả lời

9

Nói chung, không. Nó sẽ phụ thuộc vào O/S, nhưng tiêu chuẩn C nói rằng các đối số cho 'main()' phải là 'main (int argc, char ** argv)' hoặc tương đương, vì vậy trừ khi char và wchar_t là cùng một kiểu cơ bản bạn không thể làm được.

Có nói rằng, bạn có thể nhận được chuỗi đối số UTF-8 vào chương trình, chuyển đổi chúng thành UTF-16 hoặc UTF-32 và sau đó tiếp tục với cuộc sống.

Trên máy Mac (10.5.8, Leopard), tôi nhận:

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

Đó là tất cả UTF-8 mã hóa. (odx là một chương trình hex dump).

Xem thêm: Why is it that UTF-8 encoding is used when interacting with a UNIX/Linux environment

3

Trên Windows dù sao, bạn có thể có một wmain() cho UNICODE xây dựng. Không di động mặc dù. Tôi không biết nếu nền tảng GCC hoặc Unix/Linux cung cấp bất cứ điều gì tương tự.

9

Mã di động không hỗ trợ. Windows (ví dụ) hỗ trợ sử dụng wmain thay vì main, trong đó trường hợp argv được chuyển thành ký tự rộng.

2

Trên Windows, bạn có thể sử dụng tchar.h và _tmain, mà sẽ được biến thành wmain nếu biểu tượng _UNICODE được xác định tại thời gian biên dịch, hoặc chính khác. TCHAR * argv [] tương tự sẽ được mở rộng thành WCHAR * argv [] nếu unicode được định nghĩa, và char * argv [] nếu không.

Nếu bạn muốn có nền tảng chéo hoạt động chính của phương pháp, bạn có thể xác định các macro của chính mình để có cùng tác dụng.

TCHAR.h chứa một số macro tiện lợi để chuyển đổi giữa wchar và char.

3

Giả sử môi trường Linux của bạn sử dụng mã UTF-8 sau đó đoạn mã sau sẽ chuẩn bị chương trình của bạn để điều trị Unicode dễ dàng trong C++:

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

Tiếp theo, gõ wchar_t là 32-bit trong Linux, có nghĩa là nó có thể giữ các điểm mã Unicode riêng lẻ và bạn có thể sử dụng một cách an toàn loại xâu chuỗi để xử lý chuỗi cổ điển trong C++ (ký tự theo ký tự). Với cuộc gọi setlocale ở trên, chèn vào wcout sẽ tự động dịch đầu ra của bạn thành UTF-8 và giải nén từ wcin sẽ tự động dịch đầu vào UTF-8 thành UTF-32 (1 ký tự = 1 điểm mã). Vấn đề duy nhất còn lại là các chuỗi argv [i] vẫn được mã hoá UTF-8.

Bạn có thể sử dụng hàm sau để giải mã UTF-8 thành UTF-32.Nếu chuỗi đầu vào bị hỏng, nó sẽ trả về các ký tự được chuyển đổi đúng cho đến khi các quy tắc UTF-8 bị hỏng. Bạn có thể cải thiện nó nếu bạn cần báo cáo lỗi hơn. Nhưng đối với dữ liệu argv một cách an toàn có thể giả định rằng nó là đúng 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

Trên Windows, bạn có thể sử dụng GetCommandLineW()CommandLineToArgvW() để tạo ra một argv kiểu wchar_t[] mảng, ngay cả khi ứng dụng không được biên dịch cho Unicode .

Các vấn đề liên quan