string
? wstring
?
std::string
là một basic_string
templated trên a char
, và std::wstring
trê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_t
là 4 byte, trong khi trên Windows, đó là 2 byte.
Thế còn Unicode thì sao?
Vấn đề là không phải char
và 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é" char
thự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_t
mã như một bài tập)
Vì vậy, khi làm việc với char
Linux, bạn thường nên sử dụng Unicode mà không hề biết. Và như đã std::string
là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 char
và 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 char
s), 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 MultiByteToWideChar và WideCharToMultiByte 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_t
chuỗi, vì vậy ngay cả các ứng dụng lịch sử cũng sẽ có các char
chuỗi được chuyển đổi wchar_t
khi 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
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
Có thể std::string
chứ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::string
phù hợp để giữ bộ đệm 'nhị phân', trong đó a std::wstring
khô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::string
sẽ đủ để xử lý tất cả các char
chuỗi dựa trên (mỗi chuỗi char
là một số từ 0 đến 255). Nhưng:
- ASCII được cho là đi từ 0 đến 127. Cao hơn
char
KHÔNG phải là ASCII.
- a
char
từ 0 đến 127 sẽ được giữ đúng
- a
char
từ 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.
Được std::wstring
hỗ 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.
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_t
lớn hơn char
loạ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 ...).