2010-07-21 46 views
52

Tôi đang đọc về tập hợp và mã hóa charater trên Windows. Tôi nhận thấy rằng có hai cờ biên dịch trong trình biên dịch Visual Studio (cho C++) được gọi là MBCS và UNICODE. Sự khác biệt giữa chúng là gì ? Những gì tôi không nhận được là làm thế nào UTF-8 là khái niệm khác nhau từ một mã hóa MBCS? Ngoài ra, tôi tìm thấy đoạn trích sau đây trong MSDN:Sự khác biệt giữa MBCS và UTF-8 trên Windows

Unicode là một nhân vật mã hóa 16-bit

này phủ nhận bất cứ điều gì tôi đọc về Unicode. Tôi nghĩ rằng unicode có thể được mã hóa với các mã hóa khác nhau như UTF-8 và UTF-16. Ai đó có thể làm sáng tỏ thêm về sự nhầm lẫn này?

Trả lời

92

Tôi nhận thấy rằng có hai biên dịch cờ trong trình biên dịch Visual Studio (cho C++) được gọi là MBCS và UNICODE. sự khác biệt giữa chúng là gì?

Nhiều chức năng trong Windows API có hai phiên bản: Một là mất char thông số (trong một trang mã miền địa phương cụ thể) và một trong đó có wchar_t tham số (trong UTF-16).

int MessageBoxA(HWND hWnd, const char* lpText, const char* lpCaption, unsigned int uType); 
int MessageBoxW(HWND hWnd, const wchar_t* lpText, const wchar_t* lpCaption, unsigned int uType); 

Mỗi cặp chức năng này cũng có macro không có hậu tố phụ thuộc vào việc macro UNICODE có được xác định hay không.

#ifdef UNICODE 
    #define MessageBox MessageBoxW 
#else 
    #define MessageBox MessageBoxA 
#endif 

Để thực hiện công việc này, loại TCHAR được định nghĩa để loại bỏ loại ký tự được sử dụng bởi các chức năng API.

#ifdef UNICODE 
    typedef wchar_t TCHAR; 
#else 
    typedef char TCHAR; 
#endif 

Điều này, tuy nhiên, was a bad idea. Bạn phải luôn xác định rõ ràng loại ký tự.

Điều tôi không nhận được là UTF-8 là khác biệt về mặt khái niệm từ mã hóa MBCS như thế nào?

MBCS là viết tắt của "bộ ký tự nhiều byte". Đối với các đầu óc, có vẻ như UTF-8 sẽ đủ điều kiện.

Nhưng trong Windows, "MBCS" chỉ đề cập đến mã hóa ký tự có thể được sử dụng với phiên bản "A" của các hàm API của Windows. Điều này bao gồm các trang mã 932 (Shift_JIS), 936 (GBK), 949 (KS_C_5601-1987) và 950 (Big5), nhưng NOT UTF-8.

Để sử dụng UTF-8, bạn phải chuyển đổi chuỗi thành UTF-16 bằng cách sử dụng MultiByteToWideChar, gọi phiên bản "W" của hàm và gọi WideCharToMultiByte trên đầu ra. Đây là cơ bản những gì "A" chức năng thực sự làm, mà làm cho tôi tự hỏi why Windows doesn't just support UTF-8.

Không có khả năng hỗ trợ the most common character encoding làm cho phiên bản "A" của Windows API vô ích. Do đó, bạn nên luôn sử dụng chức năng "W".

Unicode là một nhân vật mã hóa 16-bit

này phủ nhận bất cứ điều gì tôi đọc về Unicode.

MSDN sai. Unicode là một bộ ký tự mã hóa 21 bit có nhiều mã hóa, phổ biến nhất là UTF-8, UTF-16 và UTF-32. (Có các mã hóa Unicode khác, chẳng hạn như GB18030, UTF-7 và UTF-EBCDIC.)

Bất cứ khi nào Microsoft đề cập đến "Unicode", chúng thực sự có nghĩa là UTF-16 (hoặc UCS-2). Đây là lý do lịch sử. Windows NT là người dùng đầu tiên của Unicode, ngược lại khi 16 bit được cho là đủ cho mọi người, và UTF-8 chỉ được sử dụng trên Kế hoạch 9. Vì vậy, UCS-2 Unicode.

+0

Cảm ơn thông tin rất hữu ích. – Naveen

+8

"Điều này là dành cho lịch sử" Tôi tự hỏi tại sao họ không sửa tài liệu của họ trong 15 năm trước. – ybungalobill

+18

Họ là Microsoft. Lịch sử là sai. Kháng chiến là vô ích. – tripleee

10

MBCS có nghĩa là Multi-Byte Character Set và mô tả bất kỳ bộ ký tự nào trong đó ký tự được mã hóa thành (có thể) lớn hơn 1 byte.

ANSI/ASCII bộ ký tự không phải là nhiều byte.

UTF-8, tuy nhiên, là mã hóa nhiều byte. Nó mã hóa bất kỳ ký tự Unicode nào dưới dạng chuỗi 1, 2, 3 hoặc 4 octet (byte).

Tuy nhiên, UTF-8 chỉ là một trong một số mã hóa bê tông có thể có của bộ ký tự Unicode. Đáng chú ý, UTF-16 là một mã khác, và là mã hóa được sử dụng bởi Windows/.NET (IIRC). Đây là sự khác biệt giữa UTF-8 và UTF-16:

  • UTF-8 mã hóa bất kỳ ký tự Unicode nào theo chuỗi 1, 2, 3 hoặc 4 byte.

  • UTF-16 mã hóa hầu hết các ký tự Unicode dưới dạng 2 byte và một số là 4 byte.

Do đó, không phải đúng là mã Unicode là ký tự 16 bit. Nó giống như một mã hóa 21-bit (hoặc thậm chí nhiều hơn những ngày này), vì nó bao gồm một bộ ký tự với các điểm mã số U+000000 lên đến U+10FFFF.

+1

Chắc chắn, nhưng trong tài liệu API Windows, họ sử dụng Unicode để có nghĩa là UTF-16. (Tôi nghi ngờ hỗ trợ cho điều đó là có giới hạn và an toàn hơn để giả định UCS-2.) Có, tiêu chuẩn Unicode vượt quá 21 bit. – Rup

+2

Tài liệu đó có thể làm cho nó trông giống như Unicode là UTF-16, tuy nhiên điều đó sẽ không chính xác (nếu có, đó là cách khác). UTF-16 chỉ là một _encoding_ của Unicode. Và có, trên thực tế chúng thực sự có nghĩa là UCS-2 chứ không phải UTF-16. Tôi không hoàn toàn chắc chắn về điều đó. – stakx

+3

Windows NT chỉ hỗ trợ UCS-2. Windows đã hỗ trợ đầy đủ UTF-16 kể từ Windows 2000, IIRC. –

13

_MBCS và _UNICODE là các macro để xác định phiên bản của thói quen TCHAR.H cần gọi. Ví dụ: nếu bạn sử dụng _tcsclen để đếm độ dài của một chuỗi, thì bộ tiền xử lý sẽ ánh xạ _tcsclen tới phiên bản khác nhau theo hai macro: _MBCS và _UNICODE.

_UNICODE & _MBCS Not Defined: strlen 
_MBCS Defined: _mbslen 
_UNICODE Defined: wcslen 

Để giải thích sự khác biệt của các hàm đếm độ dài chuỗi này, hãy xem xét ví dụ sau.
Nếu bạn có một hộp máy tính chạy phiên bản Windows đơn giản hóa Trung Quốc sử dụng GBK (trang mã 936), bạn biên dịch tệp nguồn mã hóa tệp gbk và chạy tệp.

printf("%d\n", _mbslen((const unsigned char*)"I爱你M")); 
printf("%d\n", strlen("I爱你M")); 
printf("%d\n", wcslen((const wchar_t*)"I爱你M")); 

Kết quả sẽ là 4 6 3.

Dưới đây là biểu diễn thập lục phân của I爱你M trong GBK.

GBK:    49 B0 AE C4 E3 4D 00     

_mbslen biết chuỗi này được mã hóa trong GBK, vì vậy nó có thể intepreter chuỗi một cách chính xác và nhận được kết quả đúng 4 chữ: 49 như I, B0 AE như , C4 E3 như , 4D như M.

strlen chỉ biết 0x00, vì vậy nó nhận được 6.

wcslen xem xét mảng hexdeciaml này được mã hóa trong UTF16LE, và nó đếm hai byte như một từ, vì vậy nó có được 3 chữ: 49 B0, AE C4, E3 4D.

như @xiaokaoy đã chỉ ra, người kết thúc hợp lệ duy nhất cho wcslen00 00. Do đó, kết quả không đảm bảo là 3 nếu byte sau không phải là 00.

+1

Tuyệt vời. Nhưng theo quan điểm khiêm tốn của tôi, giá trị trả về của ** wcslen ((const wchar_t *) "I 爱 你 M") ** không được đảm bảo là 3. Nếu ** 49 B0 AE C4 E3 4D 00 ** không được theo sau bởi một byte 00, ** wcslen ** sẽ trả về một giá trị lớn hơn 3. – xiaokaoy

+0

Ý tôi là, chỉ ** 00 00 ** được coi là một ký tự rộng lớn. – xiaokaoy

+2

No. ** L "I 爱 你 M" ** được đảm bảo kết thúc bằng ** 4D 00 00 00 **. Nhưng ** (const wchar_t *) "Tôi 爱 你 M" ** thì không. – xiaokaoy

4

Là chú thích cho các câu trả lời khác, MSDN có tài liệu Generic-Text Mappings in TCHAR.H với các bảng tiện dụng tóm tắt cách chỉ thị tiền xử lý _UNICODE và _MBCS thay đổi định nghĩa của các kiểu C/C++ khác nhau.

Đối với cụm từ "Unicode" và "Bộ ký tự nhiều byte", mọi người đã mô tả tác dụng là gì. Tôi chỉ muốn nhấn mạnh rằng cả hai đều là Microsoft-nói cho một số điều rất cụ thể. (Nghĩa là, chúng có nghĩa là một cái gì đó ít chung chung và đặc biệt hơn so với Windows mà người ta có thể mong đợi nếu đến từ một sự hiểu biết không phải của Microsoft về văn bản quốc tế hóa.) Những cụm từ chính xác này hiển thị và có xu hướng lấy các phần/phần riêng biệt của riêng họ tài liệu kỹ thuật của microsoft, vd trong Text and Strings in Visual C++

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