wchar_t คืออะไร?
wchar_t ถูกกำหนดให้การเข้ารหัส char ของโลแคลใด ๆ สามารถแปลงเป็นการแสดง wchar_t โดยที่ wchar_t ทุกตัวแสดงถึงจุดรหัสเดียว:
ประเภท wchar_t เป็นประเภทที่แตกต่างกันซึ่งค่าสามารถแสดงรหัสที่แตกต่างกันสำหรับสมาชิกทั้งหมดของชุดอักขระเพิ่มเติมที่ใหญ่ที่สุดที่ระบุระหว่างโลแคลที่รองรับ (22.3.1)
- C ++ [basic.fundamental] 3.9.1 / 5
สิ่งนี้ไม่ต้องการให้ wchar_t มีขนาดใหญ่พอที่จะแสดงอักขระใด ๆ จากทุกภาษาพร้อมกัน นั่นคือการเข้ารหัสที่ใช้สำหรับ wchar_t อาจแตกต่างกันระหว่างโลแคล ซึ่งหมายความว่าคุณไม่จำเป็นต้องแปลงสตริงเป็น wchar_t โดยใช้โลแคลเดียวแล้วแปลงกลับเป็น char โดยใช้โลแคลอื่น 1
เนื่องจากการใช้ wchar_t เป็นตัวแทนทั่วไประหว่างโลแคลทั้งหมดดูเหมือนจะเป็นการใช้งานหลักสำหรับ wchar_t ในทางปฏิบัติคุณอาจสงสัยว่ามันดีสำหรับอะไรถ้าไม่ใช่อย่างนั้น
ความตั้งใจและวัตถุประสงค์ดั้งเดิมของ wchar_t คือการทำให้การประมวลผลข้อความเป็นเรื่องง่ายโดยกำหนดให้ต้องมีการแมปแบบหนึ่งต่อหนึ่งจากหน่วยรหัสของสตริงไปยังอักขระของข้อความจึงอนุญาตให้ใช้อัลกอริทึมแบบง่าย ๆ เช่นเดียวกับที่ใช้ ด้วยสตริง ascii เพื่อทำงานกับภาษาอื่น ๆ
น่าเสียดายที่การใช้ถ้อยคำของข้อกำหนดของ wchar_t ถือว่าการแมปแบบหนึ่งต่อหนึ่งระหว่างอักขระและจุดรหัสเพื่อให้บรรลุสิ่งนี้ Unicode ทำลายสมมติฐานที่2ดังนั้นคุณจึงไม่สามารถใช้ wchar_t สำหรับอัลกอริทึมข้อความอย่างง่ายได้อย่างปลอดภัย
ซึ่งหมายความว่าซอฟต์แวร์พกพาไม่สามารถใช้ wchar_t เป็นตัวแทนทั่วไปสำหรับข้อความระหว่างโลแคลหรือเพื่อเปิดใช้งานการใช้อัลกอริทึมข้อความธรรมดา
วันนี้ wchar_t ใช้อะไร
ไม่มากสำหรับรหัสพกพาอยู่แล้ว ถ้า__STDC_ISO_10646__
ถูกกำหนดแล้วค่าของ wchar_t จะแทนจุดรหัส Unicode โดยตรงด้วยค่าเดียวกันในทุกภาษา ทำให้ปลอดภัยในการแปลงระหว่างสถานที่ที่กล่าวถึงก่อนหน้านี้ อย่างไรก็ตามคุณไม่สามารถพึ่งพาเพียงเพื่อตัดสินใจว่าคุณสามารถใช้ wchar_t ด้วยวิธีนี้ได้เนื่องจากในขณะที่แพลตฟอร์ม unix ส่วนใหญ่กำหนด แต่ Windows ก็ไม่ได้แม้ว่า Windows จะใช้ wchar_t locale เดียวกันในทุกภาษา
เหตุผลของ Windows ไม่ได้กำหนด__STDC_ISO_10646__
เป็นเพราะวินโดวส์ใช้ UTF-16 การเข้ารหัส wchar_t ของตนและเพราะ UTF-16 ใช้ตัวแทนคู่จะเป็นตัวแทน codepoints มากกว่า U + FFFF ซึ่งหมายความว่า UTF-16 __STDC_ISO_10646__
ไม่ได้ตอบสนองความต้องการสำหรับ
สำหรับโค้ดเฉพาะแพลตฟอร์ม wchar_t อาจมีประโยชน์มากกว่า จำเป็นต้องใช้เป็นหลักใน Windows (เช่นไฟล์บางไฟล์ไม่สามารถเปิดได้โดยไม่ใช้ชื่อไฟล์ wchar_t) แม้ว่า Windows จะเป็นแพลตฟอร์มเดียวที่เป็นจริงเท่าที่ฉันรู้ (ดังนั้นเราอาจคิดว่า wchar_t เป็น 'Windows_char_t')
ในการมองย้อนกลับ wchar_t ไม่มีประโยชน์อย่างชัดเจนสำหรับการลดความซับซ้อนในการจัดการข้อความหรือใช้เป็นพื้นที่จัดเก็บข้อความที่ไม่ขึ้นกับโลแคล รหัสพกพาไม่ควรพยายามใช้เพื่อวัตถุประสงค์เหล่านี้ โค้ดที่ไม่สามารถพกพาได้อาจพบว่ามีประโยชน์เพียงเพราะ API บางตัวต้องการ
ทางเลือก
ทางเลือกที่ฉันชอบคือการใช้สตริง C ที่เข้ารหัส UTF-8 แม้บนแพลตฟอร์มที่ไม่เป็นมิตรกับ UTF-8
วิธีนี้เราสามารถเขียนโค้ดแบบพกพาโดยใช้การแสดงข้อความทั่วไปข้ามแพลตฟอร์มใช้ประเภทข้อมูลมาตรฐานตามวัตถุประสงค์ที่ต้องการรับการสนับสนุนภาษาสำหรับประเภทเหล่านั้น (เช่นตัวอักษรสตริงแม้ว่าจะมีเทคนิคบางอย่างที่จำเป็นเพื่อให้ใช้งานได้กับคอมไพเลอร์บางตัว) การสนับสนุนไลบรารีมาตรฐานการสนับสนุนการดีบักเกอร์ (อาจจำเป็นต้องใช้เทคนิคเพิ่มเติม) ฯลฯ ด้วยอักขระแบบกว้างโดยทั่วไปแล้วจะยากหรือเป็นไปไม่ได้ที่จะได้รับทั้งหมดนี้และคุณอาจได้รับชิ้นส่วนที่แตกต่างกันบนแพลตฟอร์มที่แตกต่างกัน
สิ่งหนึ่งที่ UTF-8 ไม่มีให้คือความสามารถในการใช้อัลกอริทึมข้อความอย่างง่ายเช่นเป็นไปได้กับ ASCII ใน UTF-8 นี้ไม่เลวร้ายไปกว่าการเข้ารหัส Unicode อื่น ๆ ในความเป็นจริงอาจถือได้ว่าดีกว่าเนื่องจากการแสดงหน่วยหลายรหัสใน UTF-8 เป็นเรื่องปกติมากขึ้นดังนั้นข้อบกพร่องในการจัดการรหัสการแสดงความกว้างตัวแปรของอักขระจึงมีแนวโน้มที่จะสังเกตเห็นและแก้ไขได้มากกว่าหากคุณพยายามยึดติดกับ UTF -32 พร้อม NFC หรือ NFKC
แพลตฟอร์มจำนวนมากใช้ UTF-8 เป็นการเข้ารหัสถ่านดั้งเดิมและหลายโปรแกรมไม่ต้องการการประมวลผลข้อความที่สำคัญใด ๆ ดังนั้นการเขียนโปรแกรมที่เป็นสากลบนแพลตฟอร์มเหล่านั้นจึงแตกต่างจากการเขียนโค้ดเล็กน้อยโดยไม่คำนึงถึงความเป็นสากล การเขียนโค้ดแบบพกพาที่แพร่หลายมากขึ้นหรือการเขียนบนแพลตฟอร์มอื่น ๆ จำเป็นต้องใส่การแปลงที่ขอบเขตของ API ที่ใช้การเข้ารหัสอื่น ๆ
อีกทางเลือกหนึ่งที่ซอฟต์แวร์บางตัวใช้คือการเลือกการแสดงข้ามแพลตฟอร์มเช่นอาร์เรย์แบบสั้นที่ไม่ได้ลงชื่อซึ่งถือข้อมูล UTF-16 จากนั้นให้การสนับสนุนไลบรารีทั้งหมดและเพียงแค่ใช้ค่าใช้จ่ายในการรองรับภาษาเป็นต้น
C ++ 11 เพิ่มอักขระแบบกว้างชนิดใหม่เป็นทางเลือกแทน wchar_t, char16_t และ char32_t พร้อมคุณสมบัติภาษา / ไลบรารีของผู้ดูแล สิ่งเหล่านี้ไม่ได้รับการรับรองว่าเป็น UTF-16 และ UTF-32 แต่ฉันไม่คิดว่าการใช้งานหลัก ๆ จะใช้อย่างอื่น C ++ 11 ยังปรับปรุงการรองรับ UTF-8 ด้วยเช่นกับ UTF-8 string literals ดังนั้นจึงไม่จำเป็นต้องหลอกให้ VC ++ สร้างสตริงที่เข้ารหัส UTF-8 (แม้ว่าฉันจะดำเนินการต่อไปแทนที่จะใช้u8
คำนำหน้า) .
ทางเลือกอื่นที่ควรหลีกเลี่ยง
TCHAR: TCHAR ใช้สำหรับการย้ายโปรแกรม Windows โบราณที่ถือว่าการเข้ารหัสแบบดั้งเดิมจาก char เป็น wchar_t และจะลืมได้ดีที่สุดเว้นแต่ว่าโปรแกรมของคุณจะถูกเขียนขึ้นในพันปีก่อนหน้านี้ ไม่ใช่แบบพกพาและไม่เฉพาะเจาะจงเกี่ยวกับการเข้ารหัสและแม้แต่ประเภทข้อมูลทำให้ใช้ไม่ได้กับ API ที่ไม่ใช้ TCHAR เนื่องจากจุดประสงค์คือการย้ายข้อมูลไปที่ wchar_t ซึ่งเราได้เห็นข้างต้นไม่ใช่ความคิดที่ดีจึงไม่มีคุณค่าใด ๆ ในการใช้ TCHAR
1. อักขระที่แสดงได้ในสตริง wchar_t แต่ไม่ได้รับการสนับสนุนในโลแคลใด ๆ ไม่จำเป็นต้องแสดงด้วยค่า wchar_t เดียว ซึ่งหมายความว่า wchar_t สามารถใช้การเข้ารหัสความกว้างตัวแปรสำหรับอักขระบางตัวซึ่งเป็นการละเมิดเจตนาของ wchar_t อย่างชัดเจน แม้ว่าจะเป็นที่ถกเถียงกันอยู่ว่าอักขระที่ wchar_t แสดงได้นั้นเพียงพอที่จะบอกได้ว่าโลแคล 'รองรับ' อักขระนั้นซึ่งในกรณีนี้การเข้ารหัสความกว้างตัวแปรไม่ถูกกฎหมายและการใช้ UTF-16 ของ Window ไม่เป็นไปตามนั้น
2. Unicode ช่วยให้สามารถแสดงอักขระจำนวนมากด้วยจุดรหัสหลายจุดซึ่งจะสร้างปัญหาเดียวกันสำหรับอัลกอริทึมข้อความธรรมดาเช่นการเข้ารหัสความกว้างตัวแปร แม้ว่าจะมีการรักษามาตรฐานที่ประกอบด้วยไว้อย่างเคร่งครัด แต่อักขระบางตัวก็ยังต้องการโค้ดหลายจุด ดู: http://www.unicode.org/standard/where/