std :: chuỗi VS std :: chuỗi


741

Tôi không thể hiểu sự khác biệt giữa std::stringstd::wstring. Tôi biết wstringhỗ trợ các ký tự rộng như ký tự Unicode. Tôi đã có những câu hỏi sau đây:

  1. Khi nào tôi nên sử dụng std::wstringhơn std::string?
  2. Có thể std::stringgiữ toàn bộ bộ ký tự ASCII, bao gồm các ký tự đặc biệt không?
  3. Được std::wstringhỗ trợ bởi tất cả các trình biên dịch C ++ phổ biến?
  4. Chính xác thì " nhân vật rộng " là gì?

10
Bộ charachter ASCII không có nhiều ký tự "đặc biệt", kỳ lạ nhất có lẽ là `(backquote). std :: chuỗi có thể chứa khoảng 0,025% của tất cả các ký tự Unicode (thông thường, char 8 bit)
MSalters

3
Thông tin tốt về các ký tự rộng và loại sử dụng có thể được tìm thấy ở đây: lập trình
viên.stackexchange.com/questions/102205/iêu

14
Chà, và kể từ khi chúng tôi vào năm 2012, utf8everywhere.org đã được viết. Nó trả lời khá nhiều tất cả các câu hỏi về quyền và sai với C ++ / Windows.
Pavel Radzivilovsky

42
@MSalters: std :: string có thể chứa 100% tất cả các ký tự Unicode, ngay cả khi CHAR_BIT là 8. Nó phụ thuộc vào mã hóa của std :: string, có thể là UTF-8 ở cấp hệ thống (như hầu hết mọi nơi trừ cửa sổ ) hoặc ở cấp độ ứng dụng của bạn. Mã hóa hẹp không hỗ trợ Unicode? Không có vấn đề gì, chỉ cần không sử dụng nó, thay vào đó hãy sử dụng UTF-8.
Yakov Galka

8
Đọc tuyệt vời về chủ đề này: utf8everywhere.org
Timothy Shields

Câu trả lời:


992

string? wstring?

std::stringlà một basic_stringtemplated trên a char, và std::wstringtrên a wchar_t.

char so với wchar_t

charđược cho là giữ một ký tự, thường là ký tự 8 bit.
wchar_tđược cho là có một ký tự rộng, và sau đó, mọi thứ trở nên khó khăn:
Trên Linux, a wchar_tlà 4 byte, trong khi trên Windows, đó là 2 byte.

Thế còn Unicode thì sao?

Vấn đề là không phải charvà cũng không wchar_tđược gắn trực tiếp vào unicode.

Trên Linux?

Hãy dùng HĐH Linux: Hệ thống Ubuntu của tôi đã nhận biết được unicode. Khi tôi làm việc với một chuỗi char, nó được mã hóa nguyên bản trong UTF-8 (tức là chuỗi ký tự Unicode). Các mã sau đây:

#include <cstring>
#include <iostream>

int main(int argc, char* argv[])
{
   const char text[] = "olé" ;


   std::cout << "sizeof(char)    : " << sizeof(char) << std::endl ;
   std::cout << "text            : " << text << std::endl ;
   std::cout << "sizeof(text)    : " << sizeof(text) << std::endl ;
   std::cout << "strlen(text)    : " << strlen(text) << std::endl ;

   std::cout << "text(ordinals)  :" ;

   for(size_t i = 0, iMax = strlen(text); i < iMax; ++i)
   {
      std::cout << " " << static_cast<unsigned int>(
                              static_cast<unsigned char>(text[i])
                          );
   }

   std::cout << std::endl << std::endl ;

   // - - - 

   const wchar_t wtext[] = L"olé" ;

   std::cout << "sizeof(wchar_t) : " << sizeof(wchar_t) << std::endl ;
   //std::cout << "wtext           : " << wtext << std::endl ; <- error
   std::cout << "wtext           : UNABLE TO CONVERT NATIVELY." << std::endl ;
   std::wcout << L"wtext           : " << wtext << std::endl;

   std::cout << "sizeof(wtext)   : " << sizeof(wtext) << std::endl ;
   std::cout << "wcslen(wtext)   : " << wcslen(wtext) << std::endl ;

   std::cout << "wtext(ordinals) :" ;

   for(size_t i = 0, iMax = wcslen(wtext); i < iMax; ++i)
   {
      std::cout << " " << static_cast<unsigned int>(
                              static_cast<unsigned short>(wtext[i])
                              );
   }

   std::cout << std::endl << std::endl ;

   return 0;
}

xuất văn bản sau:

sizeof(char)    : 1
text            : olé
sizeof(text)    : 5
strlen(text)    : 4
text(ordinals)  : 111 108 195 169

sizeof(wchar_t) : 4
wtext           : UNABLE TO CONVERT NATIVELY.
wtext           : ol�
sizeof(wtext)   : 16
wcslen(wtext)   : 3
wtext(ordinals) : 111 108 233

Bạn sẽ thấy văn bản "olé" charthực sự được xây dựng bởi bốn ký tự: 110, 108, 195 và 169 (không tính số 0 ở cuối). (Tôi sẽ cho bạn học wchar_tmã như một bài tập)

Vì vậy, khi làm việc với charLinux, bạn thường nên sử dụng Unicode mà không hề biết. Và như đã std::stringlàm việc với char, vì vậy std::stringđã sẵn sàng unicode.

Lưu ý rằng std::string, giống như API chuỗi C, sẽ xem xét chuỗi "olé" có 4 ký tự, không phải ba ký tự. Vì vậy, bạn nên thận trọng khi cắt / chơi với ký tự unicode vì một số tổ hợp ký tự bị cấm trong UTF-8.

Trên Windows?

Trên Windows, điều này hơi khác một chút. Win32 đã phải hỗ trợ rất nhiều ứng dụng hoạt động cùng charvà trên các bộ mã / bảng mã khác nhau được sản xuất trên toàn thế giới, trước khi Unicode ra đời.

Vì vậy, giải pháp của họ là một điều thú vị: Nếu một ứng dụng hoạt động với char, thì chuỗi char được mã hóa / in / hiển thị trên nhãn GUI bằng cách sử dụng bộ ký tự / bảng mã cục bộ trên máy. Ví dụ: "olé" sẽ là "olé" trong Windows được bản địa hóa bằng tiếng Pháp, nhưng sẽ là một cái gì đó khác biệt trên Windows được bản địa hóa bằng cyrillic ("olй" nếu bạn sử dụng Windows-1251 ). Do đó, "ứng dụng lịch sử" thường sẽ vẫn hoạt động theo cùng một cách cũ.

Đối với các ứng dụng dựa trên Unicode, Windows sử dụng wchar_t, rộng 2 byte và được mã hóa theo UTF-16 , được mã hóa Unicode trên các ký tự 2 byte (hoặc ít nhất là UCS-2 tương thích, hầu như là điều tương tự IIRC).

Các ứng dụng sử dụng charđược gọi là "multibyte" (vì mỗi glyph bao gồm một hoặc nhiều chars), trong khi các ứng dụng sử dụng wchar_tđược gọi là "widechar" (vì mỗi glyph bao gồm một hoặc hai wchar_t. Xem API chuyển đổi MultiByteToWideCharWideCharToMultiByte Win32 để biết thêm.

Do đó, nếu bạn làm việc trên Windows, bạn rất muốn sử dụng wchar_t(trừ khi bạn sử dụng một khung ẩn, như GTK + hoặc QT ...). Thực tế là đằng sau hậu trường, Windows hoạt động với các wchar_tchuỗi, vì vậy ngay cả các ứng dụng lịch sử cũng sẽ có các charchuỗi được chuyển đổi wchar_tkhi sử dụng API như SetWindowText()(hàm API cấp thấp để đặt nhãn trên GUI Win32).

Vấn đề bộ nhớ?

UTF-32 là 4 byte cho mỗi ký tự, vì vậy không có gì nhiều để thêm, nếu chỉ có văn bản UTF-8 và văn bản UTF-16 sẽ luôn sử dụng ít hơn hoặc cùng một lượng bộ nhớ so với văn bản UTF-32 (và thường ít hơn ).

Nếu có vấn đề về bộ nhớ, thì bạn nên biết hơn so với hầu hết các ngôn ngữ phương Tây, văn bản UTF-8 sẽ sử dụng ít bộ nhớ hơn so với cùng một ngôn ngữ UTF-16.

Tuy nhiên, đối với các ngôn ngữ khác (tiếng Trung, tiếng Nhật, v.v.), bộ nhớ được sử dụng sẽ giống nhau hoặc lớn hơn một chút đối với UTF-8 so với UTF-16.

Nói chung, UTF-16 chủ yếu sẽ sử dụng 2 và đôi khi 4 byte cho mỗi ký tự (trừ khi bạn đang xử lý một loại glyphs ngôn ngữ bí truyền (Klingon? Elvish?), Trong khi UTF-8 sẽ tiêu tốn từ 1 đến 4 byte.

Xem http://en.wikipedia.org/wiki/UTF-8#Compared_to_UTF-16 để biết thêm thông tin.

Phần kết luận

  1. Khi nào tôi nên sử dụng std :: wopes over std :: string?

    Trên Linux? Hầu như không bao giờ (§).
    Trên Windows? Gần như luôn luôn (§).
    Trên mã đa nền tảng? Phụ thuộc vào bộ công cụ của bạn ...

    (§): trừ khi bạn sử dụng bộ công cụ / khung nói khác

  2. Có thể std::stringchứa tất cả các bộ ký tự ASCII bao gồm các ký tự đặc biệt không?

    Lưu ý: A std::stringphù hợp để giữ bộ đệm 'nhị phân', trong đó a std::wstringkhông!

    Trên Linux? Đúng.
    Trên Windows? Chỉ các ký tự đặc biệt có sẵn cho ngôn ngữ hiện tại của người dùng Windows.

    Chỉnh sửa (Sau khi nhận xét từ Johann Gerell ):
    a std::stringsẽ đủ để xử lý tất cả các charchuỗi dựa trên (mỗi chuỗi charlà một số từ 0 đến 255). Nhưng:

    1. ASCII được cho là đi từ 0 đến 127. Cao hơn charKHÔNG phải là ASCII.
    2. a chartừ 0 đến 127 sẽ được giữ đúng
    3. a chartừ 128 đến 255 sẽ có một dấu hiệu tùy thuộc vào mã hóa của bạn (unicode, không unicode, v.v.), nhưng nó sẽ có thể giữ tất cả các glyph Unicode miễn là chúng được mã hóa trong UTF-8.
  3. Được std::wstringhỗ trợ bởi hầu hết tất cả các trình biên dịch C ++ phổ biến?

    Hầu hết, ngoại trừ các trình biên dịch dựa trên GCC được chuyển sang Windows.
    Nó hoạt động trên g ++ 4.3.2 của tôi (trong Linux) và tôi đã sử dụng API Unicode trên Win32 kể từ Visual C ++ 6.

  4. Chính xác một nhân vật rộng là gì?

    Trên C / C ++, đây là loại ký tự được viết wchar_tlớn hơn charloại ký tự đơn giản . Nó được cho là được sử dụng để đặt bên trong các ký tự có chỉ số (như glyphs Unicode) lớn hơn 255 (hoặc 127, tùy thuộc ...).


4
@gnud: Có lẽ wchar_t được cho là đủ để xử lý tất cả các ký tự UCS-2 (hầu hết các ký tự UTF-16) trước khi UTF-16 ra đời ... Hoặc có lẽ Microsoft đã có các ưu tiên khác ngoài POSIX, như cho phép truy cập dễ dàng vào Unicode mà không sửa đổi việc sử dụng char được mã hóa trên Win32.
paercebal

4
@Sorin Sbarnea: UTF-8 có thể mất 1-6 byte, nhưng rõ ràng tiêu chuẩn giới hạn ở mức 1-4. Xem en.wikipedia.org/wiki/UTF8#Mô tả để biết thêm thông tin.
paercebal

8
Mặc dù các ví dụ này tạo ra các kết quả khác nhau trên Linux và Windows, chương trình C ++ chứa hành vi được định nghĩa triển khai về việc có olèđược mã hóa dưới dạng UTF-8 hay không. Hơn nữa, lý do bạn không thể natively dòng wchar_t *để std::coutlà bởi vì các loại không phù hợp dẫn đến một chương trình vô hình thành và nó có liên quan gì đến việc sử dụng mã hóa. Thật đáng để chỉ ra rằng bạn sử dụng std::stringhay std::wstringphụ thuộc vào sở thích mã hóa của riêng bạn chứ không phải nền tảng, đặc biệt nếu bạn muốn mã của mình có thể mang theo được.
John Leidegren

14
Windows thực sự sử dụng UTF-16 và đã có từ khá lâu, các phiên bản Windows cũ hơn đã sử dụng UCS-2 nhưng đây không còn là trường hợp nữa. Vấn đề duy nhất của tôi ở đây là kết luận std::wstringnên được sử dụng trên Windows bởi vì nó phù hợp hơn với API Unicode Windows mà tôi nghĩ là sai lầm. Nếu mối quan tâm duy nhất của bạn là gọi API Unicode của Windows và không phải là chuỗi sắp xếp thì chắc chắn nhưng tôi không mua nó như trường hợp chung.
John Leidegren

15
@ John Leidegren If your only concern was calling into the Unicode Windows API and not marshalling strings then sure:: Sau đó, chúng tôi đồng ý. Tôi đang viết mã bằng C ++, không phải JavaScript. Tránh marshalling vô dụng hoặc bất kỳ xử lý có khả năng tốn kém khác trong thời gian chạy khi nó có thể được thực hiện tại thời gian biên dịch là trung tâm của ngôn ngữ đó. Mã hóa chống lại WinAPI và sử dụng std::stringchỉ là một sự lãng phí tài nguyên thời gian chạy vô lý. Bạn thấy nó ngụy biện, và nó ổn, vì đó là quan điểm của bạn. Riêng tôi là tôi sẽ không viết mã với sự bi quan trên Windows chỉ vì nó trông tốt hơn từ phía Linux.
paercebal

71

Tôi khuyên bạn nên tránh std::wstringtrên Windows hoặc các nơi khác, ngoại trừ khi giao diện được yêu cầu hoặc bất kỳ nơi nào gần các lệnh gọi API của Windows và chuyển đổi mã hóa tương ứng dưới dạng đường cú pháp.

Quan điểm của tôi được tóm tắt trong http://utf8everywhere.org mà tôi là đồng tác giả.

Trừ khi ứng dụng của bạn là trung tâm cuộc gọi API, ví dụ chủ yếu là ứng dụng UI, đề xuất là lưu trữ chuỗi Unicode trong chuỗi std :: và được mã hóa trong UTF-8, thực hiện chuyển đổi gần các lệnh gọi API. Những lợi ích được nêu trong bài viết lớn hơn sự khó chịu rõ ràng của chuyển đổi, đặc biệt là trong các ứng dụng phức tạp. Điều này gấp đôi vì vậy để phát triển đa nền tảng và thư viện.

Và bây giờ, trả lời câu hỏi của bạn:

  1. Một vài lý do yếu. Nó tồn tại vì những lý do lịch sử, nơi mà các góa phụ được cho là cách hỗ trợ Unicode thích hợp. Hiện tại nó được sử dụng để giao diện API thích các chuỗi UTF-16. Tôi chỉ sử dụng chúng trong vùng lân cận trực tiếp của các lệnh gọi API như vậy.
  2. Điều này không có gì để làm với std :: string. Nó có thể chứa bất kỳ mã hóa nào bạn đặt trong đó. Câu hỏi duy nhất là làm thế nào bạn đối xử với nội dung của nó. Đề xuất của tôi là UTF-8, vì vậy nó sẽ có thể giữ tất cả các ký tự Unicode chính xác. Đó là một thực tế phổ biến trên Linux, nhưng tôi nghĩ các chương trình Windows cũng nên làm điều đó.
  3. Không.
  4. Nhân vật rộng là một cái tên khó hiểu. Trong những ngày đầu của Unicode, có một niềm tin rằng một ký tự có thể được mã hóa thành hai byte, do đó có tên. Ngày nay, nó là viết tắt của "bất kỳ phần nào của ký tự dài hai byte". UTF-16 được xem như một chuỗi các cặp byte như vậy (còn gọi là các ký tự Rộng). Một ký tự trong UTF-16 có một hoặc hai cặp.

37

Vì vậy, mọi độc giả ở đây bây giờ nên có một sự hiểu biết rõ ràng về sự thật, tình hình. Nếu không, thì bạn phải đọc câu trả lời toàn diện xuất sắc của paercebal [btw: cảm ơn!].

Kết luận thực dụng của tôi rất đơn giản: tất cả những thứ "mã hóa ký tự" của C ++ (và STL) đều bị phá vỡ đáng kể và vô dụng. Đổ lỗi cho Microsoft hay không, điều đó sẽ không giúp được gì.

Giải pháp của tôi, sau khi điều tra chuyên sâu, nhiều thất vọng và những trải nghiệm có hậu quả là như sau:

  1. chấp nhận, rằng bạn phải tự chịu trách nhiệm về công cụ mã hóa và chuyển đổi (và bạn sẽ thấy rằng phần lớn trong số đó là khá nhỏ)

  2. sử dụng chuỗi std :: cho mọi chuỗi được mã hóa UTF-8 (chỉ a typedef std::string UTF8String)

  3. chấp nhận rằng một đối tượng UTF8String như vậy chỉ là một container ngu ngốc, nhưng rẻ tiền. Đừng bao giờ truy cập và / hoặc thao tác trực tiếp với các ký tự trong đó (không tìm kiếm, thay thế, v.v.). Bạn có thể, nhưng bạn thực sự thực sự, thực sự không muốn lãng phí thời gian của mình để viết các thuật toán thao tác văn bản cho các chuỗi nhiều byte! Ngay cả khi những người khác đã làm những điều ngu ngốc như vậy, đừng làm điều đó! Để cho nó được! (Chà, có những kịch bản có ý nghĩa ... chỉ cần sử dụng thư viện ICU cho những cái đó).

  4. sử dụng std :: wopes cho chuỗi được mã hóa UCS-2 ( typedef std::wstring UCS2String) - đây là một sự thỏa hiệp và nhượng bộ cho mớ hỗn độn mà API WIN32 đã giới thiệu). UCS-2 là đủ cho hầu hết chúng ta (nhiều hơn về điều đó sau ...).

  5. sử dụng các phiên bản UCS2String bất cứ khi nào cần truy cập theo từng ký tự (đọc, thao tác, v.v.). Bất kỳ quá trình xử lý dựa trên ký tự nào cũng phải được thực hiện theo cách biểu diễn NON-multibyte. Nó đơn giản, nhanh chóng, dễ dàng.

  6. thêm hai chức năng tiện ích để chuyển đổi qua lại giữa UTF-8 và UCS-2:

    UCS2String ConvertToUCS2( const UTF8String &str );
    UTF8String ConvertToUTF8( const UCS2String &str );

Việc chuyển đổi rất đơn giản, google sẽ giúp đỡ ở đây ...

Đó là nó. Sử dụng UTF8String bất cứ nơi nào bộ nhớ là quý giá và cho tất cả I / O UTF-8. Sử dụng UCS2String bất cứ nơi nào chuỗi phải được phân tích cú pháp và / hoặc thao tác. Bạn có thể chuyển đổi giữa hai đại diện bất cứ lúc nào.

Lựa chọn thay thế & cải tiến

  • chuyển đổi từ & sang mã hóa ký tự một byte (ví dụ: ISO-8859-1) có thể được thực hiện với sự trợ giúp của các bảng dịch đơn giản, ví dụ const wchar_t tt_iso88951[256] = {0,1,2,...};và mã thích hợp để chuyển đổi sang & từ UCS2.

  • nếu UCS-2 không đủ, hãy chuyển sang UCS-4 ( typedef std::basic_string<uint32_t> UCS2String)

ICU hoặc các thư viện unicode khác?

Đối với công cụ tiên tiến.


Dang, thật không hay khi biết rằng hỗ trợ Unicode gốc không có ở đó.
Mihai Danila

@Frunsi, tôi tò mò muốn biết liệu bạn đã thử Glib :: ustring chưa và nếu vậy, suy nghĩ của bạn là gì?
Caroline Beltran

@CarolineBeltran: Tôi biết Glib, nhưng tôi chưa bao giờ sử dụng nó và có lẽ tôi sẽ không bao giờ sử dụng nó, vì nó khá hạn chế đối với một nền tảng mục tiêu khá không đặc biệt (hệ thống unixoid ...). Cổng windows của nó dựa trên lớp win2unix bên ngoài và IMHO hoàn toàn không có lớp tương thích OSX. Tất cả những thứ này đang hướng rõ ràng vào một hướng sai, ít nhất là đối với mã của tôi (ở cấp độ vòm này ...) ;-) Vì vậy, Glib không phải là một lựa chọn
Frunsi

9
Tìm kiếm, thay thế, v.v ... chỉ hoạt động tốt trên các chuỗi UTF-8 (một phần của chuỗi byte đại diện cho một ký tự không bao giờ có thể bị hiểu sai là một ký tự khác). Trên thực tế, UTF-16 và UTF-32 hoàn toàn không làm cho việc này trở nên dễ dàng hơn: cả ba mã hóa đều là mã hóa đa bào trong thực tế, bởi vì một ký tự nhận biết người dùng (cụm grapheme) có thể là bất kỳ số lượng mã hóa đơn mã nào dài! Giải pháp thực tế là sử dụng UTF-8 cho mọi thứ và chỉ chuyển đổi thành UTF-16 khi xử lý API Windows.
Daniel

5
@Frunsi: Tìm kiếm và thay thế hoạt động tốt như với UTF-8 như với UTF-32. Đó chính xác là vì việc xử lý văn bản nhận biết Unicode phù hợp cần phải xử lý mọi cách, mặc dù sử dụng mã hóa có độ dài thay đổi như UTF-8 không khiến việc xử lý chuỗi trở nên phức tạp hơn. Vì vậy, chỉ cần sử dụng UTF-8 ở mọi nơi. Các hàm chuỗi C thông thường sẽ hoạt động tốt trên UTF-8 (và tương ứng với các so sánh thứ tự trên chuỗi Unicode) và nếu bạn cần bất kỳ thứ gì có thể nhận biết ngôn ngữ nhiều hơn, bạn sẽ phải gọi vào thư viện Unicode, UTF-16/32 không thể cứu bạn khỏi điều đó.
Daniel

25
  1. Khi bạn muốn có các ký tự rộng được lưu trữ trong chuỗi của bạn. widephụ thuộc vào việc thực hiện. Visual C ++ mặc định là 16 bit nếu tôi nhớ chính xác, trong khi GCC mặc định tùy thuộc vào mục tiêu. Nó dài 32 bit ở đây. Xin lưu ý wchar_t (loại ký tự rộng) không liên quan gì đến unicode. Nó chỉ đảm bảo rằng nó có thể lưu trữ tất cả các thành viên của bộ ký tự lớn nhất mà việc triển khai hỗ trợ bởi các địa phương của nó và ít nhất là miễn là char. Bạn cũng có thể lưu trữ chuỗi unicode tốt std::stringbằng cách sử dụng utf-8mã hóa. Nhưng nó sẽ không hiểu ý nghĩa của các điểm mã unicode. Vì thếstr.size() sẽ không cung cấp cho bạn số lượng ký tự logic trong chuỗi của bạn, mà chỉ là số lượng phần tử char hoặc wchar_t được lưu trữ trong chuỗi / chuỗi đó. Vì lý do đó, các trình bao bọc gtk / glib C ++ đã phát triển một Glib::ustringlớp có thể xử lý utf-8.

    Nếu wchar_t của bạn dài 32 bit, thì bạn có thể sử dụng utf-32làm mã hóa unicode và bạn có thể lưu trữ xử lý các chuỗi unicode bằng cách sử dụng mã hóa cố định (utf-32 là độ dài cố định). Điều này có nghĩa là s.size()chức năng của chuỗi của bạn sau đó sẽ trả về đúng số lượng phần tử wchar_t các ký tự logic.

  2. Có, char luôn dài ít nhất 8 bit, có nghĩa là nó có thể lưu trữ tất cả các giá trị ASCII.
  3. Vâng, tất cả các trình biên dịch chính hỗ trợ nó.

Tôi tò mò về # 2. Tôi nghĩ rằng 7 bit cũng sẽ có giá trị kỹ thuật? Hoặc có yêu cầu để có thể lưu trữ bất cứ thứ gì qua ký tự ASCII 7 bit không?
jalf

1
vâng c89 chỉ định phạm vi tối thiểu cho các loại cơ bản trong tài liệu giới hạn của nó.h (đối với char không dấu, đó là 0..255 phút) và hệ thống nhị phân thuần cho các loại số nguyên. nó tuân theo char, char không dấu và char đã ký có độ dài bit tối thiểu là 8. c ++ thừa hưởng các quy tắc đó.
Julian Schaub - litb

15
"Điều này có nghĩa là hàm s.size () của chuỗi của bạn sau đó sẽ trả về đúng số lượng phần tử wchar_t và các ký tự logic." Điều này không hoàn toàn chính xác, ngay cả đối với Unicode. Sẽ chính xác hơn khi nói mật mã hơn là "ký tự logic", ngay cả trong UTF-32, một ký tự đã cho có thể bao gồm nhiều điểm mã.
Logan Capaldo

Về bản chất, các bạn có nói rằng C ++ không có hỗ trợ riêng cho bộ ký tự Unicode không?
Mihai Danila

1
"Nhưng nó sẽ không hiểu ý nghĩa của các điểm mã unicode." Trên cửa sổ, cũng không std::wstring.
Ded repeatator

5

Tôi thường xuyên sử dụng std :: string để giữ các ký tự utf-8 mà không gặp vấn đề gì cả. Tôi thực sự khuyên bạn nên làm điều này khi giao tiếp với API sử dụng utf-8 làm kiểu chuỗi gốc.

Ví dụ: tôi sử dụng utf-8 khi giao tiếp mã của tôi với trình thông dịch Tcl.

Thông báo chính là độ dài của chuỗi std ::, không còn là số lượng ký tự trong chuỗi.


1
Juan: Bạn có nghĩa là chuỗi std :: có thể chứa tất cả các ký tự unicode nhưng độ dài sẽ báo cáo không chính xác? Có một lý do mà nó báo cáo độ dài không chính xác?

3
Khi sử dụng mã hóa utf-8, một ký tự unicode có thể được tạo thành từ nhiều byte. Đây là lý do tại sao mã hóa utf-8 nhỏ hơn khi sử dụng hầu hết các ký tự từ bộ ascii tiêu chuẩn. Bạn cần sử dụng các hàm đặc biệt (hoặc tự cuộn) để đo số lượng ký tự unicode.

2
(Cụ thể của Windows) Hầu hết các chức năng sẽ mong đợi rằng một chuỗi sử dụng byte là ASCII và 2 byte là Unicode, phiên bản cũ hơn MBCS. Điều đó có nghĩa là nếu bạn đang lưu trữ unicode 8 bit, bạn sẽ phải chuyển đổi thành unicode 16 bit để gọi một hàm windows tiêu chuẩn (trừ khi bạn chỉ sử dụng phần ASCII).
Greg Domjan

2
Chuỗi std :: không chỉ báo cáo độ dài không chính xác mà còn xuất ra chuỗi sai. Nếu một số ký tự Unicode được biểu thị trong UTF-8 dưới dạng nhiều byte, mà std :: string nghĩ là các ký tự của chính nó, thì các thói quen thao tác chuỗi std :: điển hình của bạn có thể sẽ xuất ra một số ký tự lạ do việc giải thích sai của một ký tự đúng ký tự.
Mihai Danila

2
Tôi đề nghị thay đổi câu trả lời để chỉ ra rằng các chuỗi nên được coi là chỉ chứa các byte và, nếu các byte là một số mã hóa Unicode (UTF-8, UTF-16, ...), thì bạn nên sử dụng các thư viện cụ thể để hiểu cái đó. Các API dựa trên chuỗi tiêu chuẩn (độ dài, chất nền, v.v.) đều sẽ thất bại thảm hại với các ký tự đa nhân. Nếu bản cập nhật này được thực hiện, tôi sẽ xóa downvote của tôi.
Mihai Danila

4
  1. Khi bạn muốn lưu trữ các ký tự 'rộng' (Unicode).
  2. Có: 255 người trong số họ (không bao gồm 0).
  3. Đúng.
  4. Đây là một bài viết giới thiệu: http://www.joelonsoftware.com/articles/Unicode.html

11
std :: chuỗi có thể giữ 0 tốt (chỉ cần cẩn thận nếu bạn gọi phương thức c_str ())
Mr Fooz

3
Và nói đúng ra, một char không được đảm bảo là 8 bit. :) Liên kết của bạn ở # 4 là phải đọc, nhưng tôi không nghĩ nó trả lời câu hỏi. Một nhân vật rộng hoàn toàn không có gì để làm với unicode. Nó chỉ đơn giản là một nhân vật rộng lớn hơn. (Bao nhiêu rộng hơn tùy thuộc vào HĐH, nhưng thường là 16 hoặc 32 bit)
jalf

2
  1. khi bạn muốn sử dụng chuỗi Unicode và không chỉ ascii, hữu ích cho việc quốc tế hóa
  2. có, nhưng nó không chơi tốt với 0
  3. không biết gì về điều đó
  4. ký tự rộng là cách cụ thể của trình biên dịch để xử lý biểu diễn độ dài cố định của ký tự unicode, đối với MSVC, nó là ký tự 2 byte, đối với gcc tôi hiểu nó là 4 byte. và +1 cho http://www.joelonsoftware.com/articles/Unicode.html

1
2. Một chuỗi std :: có thể giữ một ký tự NULL tốt. Nó cũng có thể chứa các ký tự utf-8 và rộng.

@Juan: Điều đó khiến tôi bối rối một lần nữa. Nếu std :: string có thể giữ các ký tự unicode, điều gì đặc biệt với std :: wopes?

1
@Appu: std :: chuỗi có thể chứa các ký tự unicode UTF-8. Có một số tiêu chuẩn unicode được nhắm mục tiêu ở độ rộng ký tự khác nhau. UTf8 rộng 8 bit. Ngoài ra còn có UTF-16 và UTF-32 với chiều rộng 16 và 32 bit tương ứng
Greg D

Với một std :: wopes. Mỗi ký tự unicode có thể là một wchar_t khi sử dụng mã hóa độ dài cố định. Ví dụ: nếu bạn chọn sử dụng joel trên phương pháp phần mềm khi Greg liên kết đến. Sau đó, độ dài của chuỗi là chính xác số lượng ký tự unicode trong chuỗi. Nhưng nó chiếm nhiều không gian hơn

Tôi không nói rằng nó không thể giữ 0 '\ 0' và ý tôi là không chơi tốt là một số phương pháp có thể không cung cấp cho bạn kết quả mong đợi có chứa tất cả dữ liệu của chuỗi. Quá khắc nghiệt về số phiếu giảm.
Greg Domjan

2

Các ứng dụng không hài lòng với chỉ 256 ký tự khác nhau có các tùy chọn sử dụng các ký tự rộng (hơn 8 bit) hoặc mã hóa có độ dài thay đổi (mã hóa đa bào theo thuật ngữ C ++) như UTF-8. Các ký tự rộng thường yêu cầu nhiều không gian hơn mã hóa có độ dài thay đổi, nhưng xử lý nhanh hơn. Các ứng dụng đa ngôn ngữ xử lý số lượng lớn văn bản thường sử dụng các ký tự rộng khi xử lý văn bản, nhưng chuyển đổi nó thành UTF-8 khi lưu trữ vào đĩa.

Sự khác biệt duy nhất giữa a stringvà a wstringlà kiểu dữ liệu của các ký tự mà chúng lưu trữ. Một chuỗi lưu trữ chars có kích thước được đảm bảo tối thiểu 8 bit, do đó bạn có thể sử dụng các chuỗi để xử lý, ví dụ văn bản ASCII, ISO-8859-15 hoặc UTF-8. Tiêu chuẩn không nói gì về bộ ký tự hoặc mã hóa.

Thực tế mọi trình biên dịch đều sử dụng một bộ ký tự có 128 ký tự đầu tiên tương ứng với ASCII. Đây cũng là trường hợp với trình biên dịch sử dụng mã hóa UTF-8. Điều quan trọng cần lưu ý khi sử dụng các chuỗi trong UTF-8 hoặc một số mã hóa có độ dài thay đổi khác, là các chỉ số và độ dài được đo bằng byte, không phải bằng ký tự.

Kiểu dữ liệu của một chuỗi là wchar_t , có kích thước không được xác định trong tiêu chuẩn, ngoại trừ nó phải có kích thước tối thiểu bằng char, thường là 16 bit hoặc 32 bit. chuỗi có thể được sử dụng để xử lý văn bản trong quá trình mã hóa ký tự rộng được xác định. Bởi vì mã hóa không được xác định trong tiêu chuẩn, việc chuyển đổi giữa các chuỗi và wstrings không đơn giản. Người ta không thể giả sử các wstrings có mã hóa có độ dài cố định.

Nếu bạn không cần hỗ trợ đa ngôn ngữ, bạn có thể ổn khi chỉ sử dụng các chuỗi thông thường. Mặt khác, nếu bạn đang viết một ứng dụng đồ họa, thường thì API chỉ hỗ trợ các ký tự rộng. Sau đó, bạn có thể muốn sử dụng các ký tự rộng tương tự khi xử lý văn bản. Hãy nhớ rằng UTF-16 là một mã hóa có độ dài thay đổi, có nghĩa là bạn không thể giả sử length()trả về số lượng ký tự. Nếu API sử dụng mã hóa có độ dài cố định, chẳng hạn như UCS-2, việc xử lý trở nên dễ dàng. Chuyển đổi giữa các ký tự rộng và UTF-8 rất khó thực hiện theo cách di động, nhưng một lần nữa, API giao diện người dùng của bạn có thể hỗ trợ chuyển đổi.


Vì vậy, diễn giải đoạn đầu tiên: Ứng dụng cần nhiều hơn 256 ký tự cần sử dụng mã hóa đa bào hoặc mã hóa may_multibyte.
Ded repeatator

Nói chung, mã hóa 16 và 32 bit như UCS-2 và UCS-4 không được gọi là mã hóa đa bào. Tiêu chuẩn C ++ phân biệt giữa mã hóa đa bào và ký tự rộng. Một đại diện ký tự rộng sử dụng một số lượng cố định (thường là hơn 8) bit cho mỗi ký tự. Các mã hóa sử dụng một byte đơn để mã hóa các ký tự phổ biến nhất và nhiều byte để mã hóa phần còn lại của bộ ký tự, được gọi là mã hóa đa bào.
Seppo Enarvi

Xin lỗi, bình luận cẩu thả. Nên đã nói mã hóa chiều dài thay đổi. UTF-16 là một mã hóa có độ dài thay đổi, giống như UTF-8. Giả vờ nó không phải là một ý tưởng tồi .
Ded repeatator

Đó là một điểm hay. Không có lý do tại sao wstrings không thể được sử dụng để lưu trữ UTF-16 (thay vì UCS-2), nhưng sau đó sự tiện lợi của mã hóa có độ dài cố định bị mất.
Seppo Enarvi

2

Một câu hỏi hay! Tôi nghĩ rằng DỮ LIỆU DỮ LIỆU (đôi khi cũng có liên quan đến CHARSET ) là một CƠ CHẾ TUYỆT VỜI NHỚ để lưu dữ liệu vào tệp hoặc truyền dữ liệu qua mạng, vì vậy tôi trả lời câu hỏi này là:

1. Khi nào tôi nên sử dụng std :: wopes over std :: string?

Nếu nền tảng lập trình hoặc hàm API là một byte đơn và chúng tôi muốn xử lý hoặc phân tích một số dữ liệu Unicode, ví dụ đọc từ tệp Windows'.REG hoặc luồng 2 byte mạng, chúng ta nên khai báo biến std :: wopes một cách dễ dàng xử lý chúng. ví dụ: wopes ws = L "国 国" " lấy ký tự 'a', v.v.

2. Chuỗi std :: có thể chứa toàn bộ bộ ký tự ASCII, bao gồm các ký tự đặc biệt không?

Đúng. Nhưng hãy chú ý: American ASCII, có nghĩa là mỗi octet 0x00 ~ 0xFF là viết tắt của một ký tự, bao gồm văn bản có thể in như "123abc & * _ &" và bạn đã nói một chữ đặc biệt, chủ yếu in dưới dạng '.' tránh nhầm lẫn biên tập viên hoặc thiết bị đầu cuối. Và một số quốc gia khác mở rộng bảng mã "ASCII" của riêng họ, ví dụ như tiếng Trung Quốc, sử dụng 2 octet để thay thế cho một ký tự.

3. Là std :: wopes được hỗ trợ bởi tất cả các trình biên dịch C ++ phổ biến?

Có thể, hoặc chủ yếu. Tôi đã sử dụng: VC ++ 6 và GCC 3.3, CÓ

4. Chính xác thì "nhân vật rộng" là gì?

một ký tự rộng chủ yếu biểu thị việc sử dụng 2 octet hoặc 4 octet để giữ các ký tự của tất cả các quốc gia. 2 octet UCS2 là một mẫu đại diện, và hơn nữa, ví dụ tiếng Anh 'a', bộ nhớ của nó là 2 octet 0x0061 (so với ASCII 'bộ nhớ của a là 1 octet 0x61)


0

Có một số câu trả lời rất hay ở đây, nhưng tôi nghĩ có một vài điều tôi có thể thêm vào Windows / Visual Studio. Tis dựa trên kinh nghiệm của tôi với VS2015. Trên Linux, về cơ bản, câu trả lời là sử dụng mã hóa UTF-8 std::stringở mọi nơi. Trên Windows / VS, nó trở nên phức tạp hơn. Đây là lý do tại sao. Windows hy vọng các chuỗi được lưu trữ bằng chars sẽ được mã hóa bằng mã địa phương. Đây hầu như luôn là bộ ký tự ASCII được theo sau bởi 128 ký tự đặc biệt khác tùy thuộc vào vị trí của bạn. Hãy để tôi nói rằng điều này không chỉ khi sử dụng API Windows, có ba nơi chính khác mà các chuỗi này tương tác với C ++ tiêu chuẩn. Đây là những chuỗi ký tự, xuất ra để std::coutsử dụng <<và chuyển tên tệp tới std::fstream.

Tôi sẽ lên trước rằng tôi là một lập trình viên, không phải là một chuyên gia ngôn ngữ. Tôi đánh giá cao USC2 và UTF-16 không giống nhau, nhưng với mục đích của tôi, chúng đủ gần để có thể hoán đổi cho nhau và tôi sử dụng chúng như vậy ở đây. Tôi thực sự không chắc chắn Windows sử dụng cái gì, nhưng tôi thường không cần biết. Tôi đã nói UCS2 trong câu trả lời này, rất xin lỗi trước nếu tôi làm phiền bất cứ ai vì sự thiếu hiểu biết của tôi về vấn đề này và tôi rất vui lòng thay đổi nó nếu tôi gặp sự cố.

Chuỗi ký tự

Nếu bạn nhập chuỗi ký tự chỉ chứa các ký tự có thể được đại diện bởi codepage của bạn thì VS sẽ lưu chúng trong tệp của bạn với mã hóa 1 byte cho mỗi ký tự dựa trên codepage của bạn. Lưu ý rằng nếu bạn thay đổi bảng mã hoặc cung cấp nguồn của mình cho nhà phát triển khác bằng trang mã khác thì tôi nghĩ (nhưng chưa được kiểm tra) rằng nhân vật sẽ kết thúc khác nhau. Nếu bạn chạy mã của mình trên máy tính bằng một trang mã khác thì tôi không chắc nhân vật cũng sẽ thay đổi.

Nếu bạn nhập bất kỳ chuỗi ký tự nào không thể được đại diện bởi codepage của bạn thì VS sẽ yêu cầu bạn lưu tệp dưới dạng Unicode. Tập tin sau đó sẽ được mã hóa thành UTF-8. Điều này có nghĩa là tất cả các ký tự Non ASCII (bao gồm cả các ký tự trên bảng mã của bạn) sẽ được biểu thị bằng 2 hoặc nhiều byte. Điều này có nghĩa là nếu bạn cung cấp nguồn của mình cho người khác, nguồn sẽ trông giống như vậy. Tuy nhiên, trước khi chuyển nguồn cho trình biên dịch, VS chuyển đổi văn bản được mã hóa UTF-8 thành văn bản được mã hóa trang mã và bất kỳ ký tự nào bị thiếu trong trang mã đều được thay thế bằng? .

Cách duy nhất để đảm bảo đại diện chính xác cho một chuỗi ký tự Unicode trong VS là đi trước chuỗi ký tự bằng cách Lbiến nó thành một chuỗi ký tự rộng. Trong trường hợp này, VS sẽ chuyển đổi văn bản được mã hóa UTF-8 từ tệp thành UCS2. Sau đó, bạn cần chuyển chuỗi ký tự này thành một hàm std::wstringtạo hoặc bạn cần chuyển đổi nó thành utf-8 và đặt nó vào một std::string. Hoặc nếu bạn muốn, bạn có thể sử dụng các hàm Windows API để mã hóa nó bằng trang mã của bạn để đặt nó vàostd::string , nhưng sau đó bạn cũng có thể không sử dụng một chuỗi ký tự rộng.

std :: cout

Khi xuất ra bàn điều khiển bằng cách sử dụng, <<bạn chỉ có thể sử dụng std::stringchứ không phải std::wstringvà văn bản phải được mã hóa bằng bảng mã địa phương của bạn. Nếu bạn có std::wstringthì bạn phải chuyển đổi nó bằng một trong các hàm API của Windows và mọi ký tự không có trong bảng mã của bạn sẽ được thay thế bằng? (có thể bạn có thể thay đổi ký tự, tôi không thể nhớ).

std :: tên tập tin

Hệ điều hành Windows sử dụng UCS2 / UTF-16 cho tên tệp của nó, vì vậy dù là bảng mã của bạn, bạn có thể có các tệp với bất kỳ ký tự Unicode nào. Nhưng điều này có nghĩa là để truy cập hoặc tạo các tệp có ký tự không có trong bảng mã của bạn, bạn phải sử dụng std::wstring. Không có cách nào khác. Đây là một phần mở rộng cụ thể của Microsoft để std::fstreamcó thể sẽ không biên dịch trên các hệ thống khác. Nếu bạn sử dụng std :: string thì bạn chỉ có thể sử dụng tên tệp chỉ bao gồm các ký tự trên bảng mã của bạn.

Lựa chọn của bạn

Nếu bạn chỉ làm việc trên Linux thì có lẽ bạn đã không đạt được điều này. Chỉ cần sử dụng UTF-8 std::stringở mọi nơi.

Nếu bạn chỉ làm việc trên Windows, chỉ cần sử dụng UCS2 std::wstringở mọi nơi. Một số người theo chủ nghĩa thuần túy có thể nói sử dụng UTF8 sau đó chuyển đổi khi cần, nhưng tại sao phải bận tâm với rắc rối.

Nếu bạn là một nền tảng chéo thì thật là một mớ hỗn độn. Nếu bạn cố gắng sử dụng UTF-8 ở mọi nơi trên Windows thì bạn cần phải thực sự cẩn thận với chuỗi ký tự và xuất ra bảng điều khiển. Bạn có thể dễ dàng làm hỏng chuỗi của bạn ở đó. Nếu bạn sử dụng std::wstringở mọi nơi trên Linux thì bạn có thể không có quyền truy cập vào phiên bản rộng std::fstream, vì vậy bạn phải thực hiện chuyển đổi, nhưng không có nguy cơ tham nhũng. Vì vậy, cá nhân tôi nghĩ rằng đây là một lựa chọn tốt hơn. Nhiều người sẽ không đồng ý, nhưng tôi không đơn độc - ví dụ như con đường của wxWidgets.

Một tùy chọn khác có thể là typedef unicodestringnhư std::stringtrên Linux và std::wstringtrên Windows và có một macro có tên UNI () có tiền tố L trên Windows và không có gì trên Linux, sau đó là mã

#include <fstream>
#include <string>
#include <iostream>
#include <Windows.h>

#ifdef _WIN32
typedef std::wstring unicodestring;
#define UNI(text) L ## text
std::string formatForConsole(const unicodestring &str)
{
    std::string result;
    //Call WideCharToMultiByte to do the conversion
    return result;
}
#else
typedef std::string unicodestring;
#define UNI(text) text
std::string formatForConsole(const unicodestring &str)
{
    return str;
}
#endif

int main()
{

    unicodestring fileName(UNI("fileName"));
    std::ofstream fout;
    fout.open(fileName);
    std::cout << formatForConsole(fileName) << std::endl;
    return 0;
}

Tôi nghĩ sẽ ổn trên cả hai nền tảng.

Đáp án

Vì vậy, để trả lời câu hỏi của bạn

1) Nếu bạn đang lập trình cho Windows, thì mọi lúc, nếu đa nền tảng thì có thể mọi lúc, trừ khi bạn muốn xử lý các vấn đề tham nhũng có thể có trên Windows hoặc viết một số mã với nền tảng cụ thể #ifdefsđể khắc phục sự khác biệt, nếu chỉ sử dụng Linux thì không bao giờ.

2) Có. Ngoài ra, trên Linux, bạn cũng có thể sử dụng nó cho tất cả Unicode. Trên Windows, bạn chỉ có thể sử dụng nó cho tất cả unicode nếu bạn chọn mã hóa thủ công bằng UTF-8. Nhưng các API Windows và các lớp C ++ tiêu chuẩn sẽ mong muốn std::stringđược mã hóa bằng cách sử dụng bảng mã địa phương. Điều này bao gồm tất cả ASCII cộng với 128 ký tự khác thay đổi tùy theo bộ mã mà máy tính của bạn được thiết lập để sử dụng.

3) Tôi tin là như vậy, nhưng nếu không thì đó chỉ là một kiểu đánh máy đơn giản của một 'std :: basic_opes' sử dụng wchar_tthay vìchar

4) Ký tự rộng là loại ký tự lớn hơn charloại chuẩn 1 byte . Trên Windows là 2 byte, trên Linux là 4 byte.


1
Về "Tuy nhiên, trước khi chuyển nguồn cho trình biên dịch, VS chuyển đổi văn bản được mã hóa UTF-8 thành văn bản được mã hóa trang mã và bất kỳ ký tự nào bị thiếu trong trang mã được thay thế bằng?" -> Tôi không nghĩ rằng điều này đúng khi trình biên dịch sử dụng mã hóa UTF-8 (sử dụng /utf-8).
Roi Danton

Tôi đã không nhận thức được điều này như là một lựa chọn. Từ liên kết này docs.microsoft.com/en-us/cpp/build/reference/ nam dường như không có hộp đánh dấu để chọn trong thuộc tính dự án, bạn phải thêm nó dưới dạng tùy chọn dòng lệnh bổ sung. Điểm tốt!
Phil Rosenberg

-2

1) Như Greg đã đề cập, wopes rất hữu ích cho việc quốc tế hóa, đó là khi bạn sẽ phát hành sản phẩm của mình bằng các ngôn ngữ khác ngoài tiếng Anh

4) Kiểm tra điều này cho nhân vật rộng http://en.wikipedia.org/wiki/Wide_character


-6

Khi nào bạn KHÔNG nên sử dụng các ký tự rộng?

Khi bạn viết mã trước năm 1990.

Rõ ràng, tôi đang bị lật, nhưng thực sự, bây giờ là thế kỷ 21. 127 ký tự từ lâu đã không còn đủ. Có, bạn có thể sử dụng UTF8, nhưng tại sao phải bận tâm với những cơn đau đầu?


16
@dave: Tôi không biết UTF-8 tạo ra cái gì đau đầu hơn so với Widechars (UTF-16). trong UTF-16, bạn cũng có nhiều nhân vật.
Pavel Radzivilovsky

Vấn đề là nếu bạn ở bất cứ nơi nào ngoài quốc gia nói tiếng Anh, bạn hãy sử dụng wchar_t. Chưa kể rằng một số bảng chữ cái có nhiều ký tự hơn bạn có thể vừa với một byte. Chúng tôi đã ở đó, trên DOS. Bệnh tâm thần phân liệt Codepage, không, cảm ơn, không còn nữa ..
Swift - Thứ Sáu Pie

1
@Swift Vấn đề với wchar_tlà kích thước và ý nghĩa của nó là dành riêng cho hệ điều hành. Nó chỉ hoán đổi những vấn đề cũ với những cái mới. Trong đó a charcharbất kể HĐH (ít nhất là trên các nền tảng tương tự). Vì vậy, chúng tôi có thể chỉ cần sử dụng UTF-8, đóng gói mọi thứ thành các chuỗi charvà than thở về việc C ++ hoàn toàn tự chúng tôi sử dụng mà không cần bất kỳ phương pháp tiêu chuẩn nào để đo lường, lập chỉ mục, tìm kiếm vv trong các chuỗi như vậy.
gạch dưới

1
@Swift Bạn dường như có nó hoàn toàn ngược. wchar_tlà kiểu dữ liệu có chiều rộng cố định, vì vậy một mảng 10 wchar_tsẽ luôn chiếm các sizeof(wchar_t) * 10byte nền tảng. Và UTF-16 là một mã hóa có chiều rộng thay đổi, trong đó các ký tự có thể được tạo thành từ 1 hoặc 2 mật mã 16 bit (và s / 16/8 / g cho UTF-8).
gạch dưới

1
@SteveHollasch đại diện chuỗi wchar_t trên windows sẽ mã hóa các ký tự lớn hơn FFFF dưới dạng cặp thay thế đặc biệt, khác sẽ chỉ lấy một phần tử wchar_t. Vì vậy, biểu diễn đó sẽ không tương thích với biểu diễn được tạo bởi trình biên dịch gnu (trong đó tất cả các ký tự nhỏ hơn FFFF sẽ không có từ nào ở phía trước chúng). Những gì được lưu trữ trong wchar_t được xác định bởi lập trình viên và trình biên dịch, chứ không phải theo một thỏa thuận nào đó
Swift - Thứ Sáu Pie
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.