string
? wstring
?
std::string
เป็นbasic_string
เทมเพลตบนchar
และบนstd::wstring
wchar_t
char
เมื่อเทียบกับ wchar_t
char
ควรจะถือตัวละครมักจะเป็นตัวละคร 8 บิต
wchar_t
ควรถือตัวกว้างและจากนั้นสิ่งที่ยุ่งยาก:
บน Linux, a wchar_t
คือ 4 ไบต์, ในขณะที่บน Windows, มันคือ 2 ไบต์
ปัญหาคือว่าไม่ว่าchar
มิได้wchar_t
มีการเชื่อมโยงโดยตรงกับ Unicode
บน Linux?
ลองใช้ระบบปฏิบัติการ Linux: ระบบ Ubuntu ของฉันเป็น unicode ที่ทราบแล้ว เมื่อฉันทำงานกับสตริงถ่านมันถูกเข้ารหัสในUTF-8 (เช่น Unicode string chars) รหัสต่อไปนี้:
#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;
}
เอาต์พุตข้อความต่อไปนี้:
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
คุณจะเห็นข้อความ "olé" char
สร้างขึ้นโดยตัวอักษรสี่ตัว: 110, 108, 195 และ 169 (ไม่นับศูนย์ต่อท้าย) ฉันจะให้คุณเรียนwchar_t
โค้ดเป็นการออกกำลังกาย)
ดังนั้นเมื่อทำงานกับchar
ลีนุกซ์คุณควรลงเอยด้วยการใช้ Unicode โดยที่ไม่รู้ตัว และstd::string
ทำงานร่วมกับchar
ดังนั้นstd::string
พร้อมใช้งาน Unicode
สังเกตได้ว่า std::string
เช่นเดียวกับ C string API จะพิจารณาสตริง "olé" ให้มี 4 ตัวอักษรไม่ใช่สามตัว ดังนั้นคุณควรระมัดระวังเมื่อตัดทอน / เล่นกับ unicode chars เนื่องจากการรวมกันของ chars บางอย่างเป็นสิ่งต้องห้ามใน UTF-8
บน Windows?
บน Windows มันแตกต่างกันเล็กน้อย Win32 ต้องสนับสนุนแอพพลิเคชันจำนวนมากที่ทำงานกับchar
และในcharsets / codepages ที่แตกต่างกันผลิตในโลกก่อนที่ Unicode จะมาถึง
ดังนั้นวิธีการแก้ปัญหาของพวกเขาจึงเป็นสิ่งที่น่าสนใจ: หากแอปพลิเคชันทำงานด้วยchar
ดังนั้นสตริงอักขระจะถูกเข้ารหัส / พิมพ์ / แสดงบนฉลาก GUI โดยใช้ charset / codepage บนเครื่อง ตัวอย่างเช่น "olé" จะเป็น "olé" ใน Windows ที่แปลเป็นภาษาฝรั่งเศส แต่จะเป็นสิ่งที่แตกต่างใน Windows ที่แปลด้วยภาษาซิริลลิก ("olй" ถ้าคุณใช้Windows-1251 ) ดังนั้น "แอปในอดีต" จึงยังคงใช้งานได้เหมือนเดิม
สำหรับแอพพลิเคชั่นที่ใช้ Unicode Windows จะใช้wchar_t
ความกว้าง 2 ไบต์และเข้ารหัสในUTF-16ซึ่งเป็น Unicode เข้ารหัสด้วยอักขระ 2 ไบต์ (หรืออย่างน้อยที่สุด UCS-2 ที่เข้ากันได้ส่วนใหญ่ซึ่งเกือบจะเป็น สิ่งเดียวกัน IIRC)
แอปพลิเคชันที่ใช้char
จะกล่าวว่า "หลายไบต์" (เพราะแต่ละสัญลักษณ์ประกอบด้วยหนึ่งหรือมากกว่านั้นchar
) ในขณะที่แอปพลิเคชันที่ใช้wchar_t
จะพูดว่า "widechar" (เพราะแต่ละสัญลักษณ์ประกอบด้วยหนึ่งหรือสองwchar_t
ไฟล์ดูMultiByteToWideCharและWideCharToMultiByte Win32 API สำหรับข้อมูลเพิ่มเติม
ดังนั้นหากคุณทำงานบน Windows คุณต้องการที่จะใช้อย่างรุนแรงwchar_t
(เว้นแต่คุณจะใช้กรอบการซ่อนเช่นGTK +หรือQT ... ) ความจริงก็คือว่าเบื้องหลัง Windows ทำงานกับwchar_t
สตริงดังนั้นแม้แต่แอปพลิเคชันในอดีตจะมีการchar
แปลงสตริงของพวกเขาwchar_t
เมื่อใช้ API เช่นSetWindowText()
(ฟังก์ชั่น API ระดับต่ำเพื่อตั้งค่าฉลากบน Win32 GUI)
ปัญหาหน่วยความจำ?
UTF-32 คือ 4 ไบต์ต่อตัวอักษรดังนั้นจึงไม่มีอะไรเพิ่มถ้าข้อความ UTF-8 และข้อความ UTF-16 จะใช้หน่วยความจำน้อยกว่าหรือเท่ากับจำนวนข้อความ UTF-32 เสมอ (และมักจะน้อยกว่า )
หากมีปัญหาเกี่ยวกับหน่วยความจำคุณควรรู้มากกว่าภาษาตะวันตกส่วนใหญ่ข้อความ UTF-8 จะใช้หน่วยความจำน้อยกว่า UTF-16 อันเดียวกัน
สำหรับภาษาอื่น (จีนญี่ปุ่นและอื่น ๆ ) หน่วยความจำที่ใช้จะเหมือนกันหรือใหญ่กว่าสำหรับ UTF-8 เล็กน้อยสำหรับ UTF-16
โดยรวมแล้ว UTF-16 ส่วนใหญ่จะใช้ 2 และ 4 ไบต์ต่ออักขระเป็นครั้งคราว (เว้นแต่คุณกำลังติดต่อกับร่ายมนตร์ภาษาลึกลับบางอย่าง (Klingon? Elvish?) ในขณะที่ UTF-8 จะใช้เวลา 1 ถึง 4 ไบต์
ดูhttp://en.wikipedia.org/wiki/UTF-8#Compared_to_UTF-16สำหรับข้อมูลเพิ่มเติม
ข้อสรุป
เมื่อใดที่ฉันควรใช้ std :: wstring บน std :: string?
บน Linux? แทบจะไม่เคย (§).
บน Windows? เกือบตลอดเวลา (§).
เกี่ยวกับรหัสข้ามแพลตฟอร์ม? ขึ้นอยู่กับชุดเครื่องมือของคุณ ...
(§): ยกเว้นว่าคุณใช้ชุดเครื่องมือ / กรอบงานที่พูดเป็นอย่างอื่น
สามารถstd::string
เก็บชุดอักขระ ASCII ทั้งหมดรวมถึงอักขระพิเศษได้หรือไม่
ประกาศ: A std::string
เหมาะสำหรับเก็บบัฟเฟอร์ 'ไบนารี' โดยที่std::wstring
ไม่ใช่!
บน Linux? ใช่.
บน Windows? เฉพาะอักขระพิเศษที่มีอยู่สำหรับสถานที่ปัจจุบันของผู้ใช้ Windows
แก้ไข (หลังจากความคิดเห็นจากJohann Gerell ):
a std::string
จะเพียงพอที่จะจัดการกับchar
สตริงที่ใช้ทั้งหมด(แต่ละอันchar
มีค่าตั้งแต่ 0 ถึง 255) แต่:
- ASCII ควรจะไปจาก 0 ถึง 127
char
s ที่สูงกว่าไม่ใช่ ASCII
- a
char
ตั้งแต่ 0 ถึง 127 จะจัดขึ้นอย่างถูกต้อง
char
128-255 จะมีความหมายขึ้นอยู่กับการเข้ารหัสของคุณ (Unicode, ไม่ใช่ Unicode, ฯลฯ ) แต่ก็จะสามารถที่จะถือทุกร่ายมนตร์ Unicode ตราบเท่าที่พวกเขาจะถูกเข้ารหัส UTF-8
คือการstd::wstring
ได้รับการสนับสนุนโดยเกือบทั้งหมดนิยม C ++ คอมไพเลอร์?
ส่วนใหญ่มีข้อยกเว้นของคอมไพเลอร์ที่ใช้ GCC ที่พอร์ตไปยัง Windows
มันทำงานบน g ++ 4.3.2 ของฉัน (ภายใต้ Linux) และฉันใช้ Unicode API บน Win32 ตั้งแต่ Visual C ++ 6
ตัวกว้างคืออะไร?
บน C / C ++ เป็นชนิดอักขระที่เขียนwchar_t
ซึ่งมีขนาดใหญ่กว่าchar
ชนิดอักขระแบบง่าย ควรใช้เพื่อใส่อักขระที่มีดัชนี (เช่น Unicode glyphs) ที่มีขนาดใหญ่กว่า 255 (หรือ 127 ขึ้นอยู่กับ ... )