2015-05-07 26 views
9

Tôi đã đọc một số bài viết về Unicode và nhận ra tôi vẫn còn nhầm lẫn những gì chính xác làm về nó.C++ string literal vẫn còn khó hiểu

Là một lập trình viên C++ trên nền tảng Windows, các môn học được trao cho tôi hầu như giống với bất kỳ giáo viên nào: luôn sử dụng bộ ký tự Unicode; templatize nó hoặc sử dụng TCHAR nếu có thể; thích wchar_t, std :: wstring trên char, std :: string.

#include <tchar.h> 
#include <string> 
typedef std::basic_string<TCHAR> tstring; 
// ... 
static const char* const s_hello = "핼로"; // bad 
static const wchar_t* const s_wchar_hello = L"핼로" // better 
static LPCTSTR s_tchar_hello = TEXT("핼로") // even better 
static const tstring s_tstring_hello(TEXT("핼로")); // best 

Bằng cách nào đó tôi đã sai lầm và tôi tự tin rằng nếu tôi nói "cái gì đó", có nghĩa là định dạng ASCII và nếu tôi nói L "cái gì đó" là Unicode. Sau đó, tôi đọc điều này:

Loại wchar_t là một loại riêng biệt có giá trị có thể đại diện cho các mã riêng biệt được chỉ định trong các ngôn ngữ được hỗ trợ (22.3.1). Loại wchar_t phải có cùng kích thước, ký kết và yêu cầu căn chỉnh (3.11) là một trong các kiểu tích phân khác, được gọi là kiểu cơ bản của nó. Các kiểu char16_t và char32_t biểu thị các kiểu riêng biệt với cùng kích cỡ, ký kết và căn chỉnh là uint_least16_t và uint_least32_t, tương ứng, được gọi là các kiểu cơ bản.

Vậy thì sao? Nếu ngôn ngữ của tôi nói bắt đầu từ mã 949, phần mở rộng của wchar_t là từ 949 + 2^(sizeof (wchar_t) * 8)? Và cách nó phát ra âm thanh như 'Tôi không quan tâm nếu việc bạn thực hiện C++ sử dụng mã hóa UTF hay cái gì'.

Ít nhất, tôi có thể hiểu rằng mọi thứ phụ thuộc vào ngôn ngữ mà ứng dụng đang bật. Vì vậy, tôi đã thử nghiệm:

#define TEST_OSTREAM_PRINT(x) \ 
std::cout << "----" << std::endl; \ 
std::cout << "cout : " << x << std::endl; \ 
std::wcout << "wcout : " << L##x << std::endl; 

int main() 
{ 
    std::ostream& os = std::cout; 

    std::cout << " * Info : " << std::endl 
       << "  sizeof(char) : " << sizeof(char) << std::endl 
       << "  sizeof(wchar_t) : " << sizeof(wchar_t) << std::endl 
       << "  littel endian? : " << IsLittelEndian() << std::endl; 
    std::cout << " - LC_ALL: " << setlocale(LC_ALL, NULL) << std::endl; 
    std::cout << " - LC_CTYPE: " << setlocale(LC_CTYPE, NULL) << std::endl; 

    TEST_OSTREAM_PRINT("핼로"); 
    TEST_OSTREAM_PRINT("おはよう。"); 
    TEST_OSTREAM_PRINT("你好"); 
    TEST_OSTREAM_PRINT("resume"); 
    TEST_OSTREAM_PRINT("résumé"); 

    return 0; 
} 

Sau đó, đầu ra là:

Info 
sizeof(char) = 1 
sizeof(wchar_t) = 2 
LC_ALL = C 
LC_CTYPE = C 
---- 
cout : 핼로 
wcout : ---- 
cout : おはよう。 
wcout : ---- 
cout : ?好 
wcout : ---- 
cout : resume 
wcout : resume 
---- 
cout : r?sum? 
wcout : r?um 

Một đầu ra với locale Hàn Quốc:

Info 
sizeof(char) = 1 
sizeof(wchar_t) = 2 
LC_ALL = Korean_Korea.949 
LC_CTYPE = Korean_Korea.949 
---- 
cout : 핼로 
wcout : 핼로 
---- 
cout : おはよう。 
wcout : おはよう。 
---- 
cout : ?好 
wcout : ---- 
cout : resume 
wcout : resume 
---- 
cout : r?sum? 
wcout : resume 

Một đầu ra:

Info 
sizeof(char) = 1 
sizeof(wchar_t) = 2 
LC_ALL = fr-FR 
LC_CTYPE = fr-FR 
---- 
cout : CU·I 
wcout : ---- 
cout : ªªªIªeª|¡£ 
wcout : ---- 
cout : ?u¿ 
wcout : ---- 
cout : resume 
wcout : resume 
---- 
cout : r?sum? 
wcout : resume 

Hóa ra Nếu tôi không cung cấp đúng ngôn ngữ, ứng dụng không xử lý phạm vi nhất định của nhân vật, không có vấn đề tôi sử dụng char hoặc wchar_t. Đó không chỉ là vấn đề. Visual studio đưa ra cảnh báo:

warning C4566: character represented by universal-character-name '\u4F60' cannot be represented in the current code page (949) 

Tôi không chắc chắn nếu điều này mô tả những gì tôi nhận được là đầu ra hay cái gì khác.

Câu hỏi. Điều gì sẽ là thực hành tốt nhất và tại sao? Làm thế nào người ta có thể làm cho một nền tảng ứng dụng/thực hiện/quốc gia độc lập? những gì chính xác xảy ra với chuỗi chữ trên nguồn? giá trị chuỗi được giải thích bằng ứng dụng như thế nào?

+1

Để có khả năng tương thích tối đa: Giữ các ký tự trong nguồn của bạn với các ký tự ASCII rất cơ bản. Sử dụng mã hóa UTF8 bằng cách sử dụng byte được xác định bằng \ x trong chuỗi. Công cụ u8 "\ u1234" mới trong phiên bản mới nhất của C++ sẽ làm cho việc này trở nên dễ dàng hơn, nhưng nó chưa được Visual Studio hỗ trợ. Xem thêm câu hỏi này: http://stackoverflow.com/questions/3768363/character-sets-not-clear – JCx

+1

'TCHAR' s là một rắc rối khổng lồ. Trừ khi bạn đang tìm kiếm để hỗ trợ các phiên bản Windows thực sự cũ, chỉ cần cung cấp cho Windows chuỗi rộng. Để tương thích với những thứ khác, bạn có thể lưu trữ các chuỗi bằng cách sử dụng UTF-8 và chuyển đổi chúng khi sử dụng chức năng Windows API. – chris

Trả lời

3

C++ không hỗ trợ Unicode bình thường. Bạn không thể sử dụng ứng dụng toàn cầu hóa bình thường trong C++ mà không sử dụng thư viện của bên thứ 3. Đọc this SO trả lời sâu sắc. Nếu bạn thực sự cần viết một ứng dụng sử dụng Unicode, tôi sẽ xem thư viện ICU.

2

Trên Windows, Microsoft guarantees rằng wchar_t hỗ trợ Unicode, vì vậy L"핼로" là cách chính xác để tạo ra chuỗi ký tự UTF-16 là const wchar_t*.Trên các nền tảng khác, điều này không nhất thiết phải giữ và bạn nên sử dụng các chuỗi ký tự Unicode C++ 11 (u8"...", u"..."U"...") nếu bạn cần mã di động — ví dụ: sử dụng u8"핼로" để tạo UTF-8 được mã hóa const char* (như của Visual Studio 2015).

Sự cố khác mà bạn đang gặp phải là cách Visual Studio diễn giải mã hóa tệp nguồn của bạn. Ví dụ: được mã hóa là 0xAA 0xAA trong EUC-KR (mã trang 949), là mã hóa cho ªª trong trang mã 1252 (fr-FR) —đó là, nếu bạn đã lưu tệp nguồn có chứa trong EUC-KR nhưng biên dịch nó trong một miền địa phương fr-FR, chữ của bạn sẽ mã hóa ªª.

Nếu bạn cần bao gồm các ký tự không phải ASCII trong nguồn của mình, bạn nên lưu chúng bằng UTF (tức là UTF-8/16/32) với BOM rõ ràng — được mô tả trong answer to this question.

+0

Bạn nói đúng. Tôi sắp kết luận rằng Microsoft sẽ chuyển đổi chuỗi ký tự rộng (L "Something") thành UCS-2, và bất cứ thứ gì bên ngoài BMP sẽ làm cho chúng trở nên điên rồ. Tuy nhiên, thử nghiệm bổ sung cho tôi biết rằng chúng thực sự được hiểu là UTF-16 đúng cách. Cảm ơn. – user2883715

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