C ++ wchar_t और wstrings के साथ "गलत" क्या है? व्यापक पात्रों के लिए कुछ विकल्प क्या हैं?


86

मैं सी ++ समुदाय (विशेष रूप से ## c ++ freenode पर) में बहुत से लोगों को देखा है के उपयोग के क्रोध wstringsऔर wchar_t, और Windows API में उनके उपयोग। के साथ wchar_tऔर wstring, और अगर मैं अंतर्राष्ट्रीयकरण का समर्थन करना चाहता हूं, तो व्यापक पात्रों के लिए कुछ विकल्प क्या हैं?


1
उसके लिए कोई संदर्भ है?
दानी

14
शायद यह भयानक धागा आपके सभी सवालों का जवाब देगा? stackoverflow.com/questions/402283/stdwstring-vs-stdstring
MrFox

15
विंडोज पर, आपके पास वास्तव में कोई विकल्प नहीं है। इसके आंतरिक API को UCS-2 के लिए डिज़ाइन किया गया था, जो उस समय से उचित था, जब यह चर-लंबाई UTF-8 और UTF-16 एन्कोडिंग के मानकीकृत होने से पहले था। लेकिन अब जब वे UTF-16 का समर्थन करते हैं, तो वे दोनों दुनिया के सबसे बुरे लोगों के साथ समाप्त हो गए हैं।
jamesdlin

12
utf8everywhere.org में व्यापक पात्रों से बचने के कारणों की अच्छी चर्चा है।
जोज

5
@jamesdlin निश्चित रूप से आपके पास एक विकल्प है। नायाब लाइब्रेरी एपीआई में गुजरते समय तार बदलने के लिए एक सुविधाजनक तरीका प्रदान करती है। स्ट्रिंग्स के साथ एपीआई कॉल आमतौर पर कम-आवृत्ति होती है, इसलिए उचित तरीका यह है कि एड-हॉक को परिवर्तित किया जाए और हर समय UTF-8 में फाइलें और आंतरिक चर हों।
पावेल रेड्ज़विलोव्स्की

जवाबों:


114

Wchar_t क्या है?

wchar_t को इस तरह परिभाषित किया जाता है कि किसी भी लोकेल के चार्ट को एन्कोडिंग को wchar_t प्रतिनिधित्व में बदला जा सकता है, जहाँ हर wchar_t एक कोडपॉइंट का प्रतिनिधित्व करता है:

टाइप wchar_t एक अलग प्रकार है, जिसका मान समर्थित स्थानों (22.3.1) के बीच निर्दिष्ट सबसे बड़े विस्तारित वर्ण सेट के सभी सदस्यों के लिए अलग कोड का प्रतिनिधित्व कर सकता है।

                                                                               - सी ++ [बेसिक.फंडमेंटल] 3.9.1 / 5

इसके लिए यह आवश्यक नहीं है कि wchar_t एक साथ सभी स्थानों से किसी भी वर्ण का प्रतिनिधित्व करने के लिए पर्याप्त हो। यही है, wchar_t के लिए उपयोग की जाने वाली एन्कोडिंग स्थानों के बीच भिन्न हो सकती है। जिसका अर्थ है कि आप आवश्यक रूप से एक स्ट्रिंग को एक लोकेल का उपयोग करके wchar_t में नहीं बदल सकते हैं और फिर किसी अन्य लोकेल का उपयोग करके चार में बदल सकते हैं। 1

सभी स्थानों के बीच एक सामान्य प्रतिनिधित्व के रूप में wchar_t का उपयोग करने के बाद से व्यवहार में wchar_t के लिए प्राथमिक उपयोग प्रतीत होता है, आप आश्चर्यचकित हो सकते हैं कि यह क्या है के लिए अच्छा है।

Wchar_t का मूल इरादा और उद्देश्य टेक्स्ट प्रोसेसिंग को सरल बनाकर इसे इस तरह परिभाषित करना था कि इसके लिए एक स्ट्रिंग की कोड-यूनिट्स से टेक्स्ट के कैरेक्टर्स तक एक-से-एक मैपिंग की आवश्यकता होती है, इस प्रकार उसी सरल एल्गोरिदम का उपयोग करने की अनुमति मिलती है। अन्य भाषाओं के साथ काम करने के लिए अस्सी के तार के साथ।

दुर्भाग्य से wchar_t के विनिर्देशन के शब्दों को इसे प्राप्त करने के लिए पात्रों और कोडपॉइंट्स के बीच एक-से-एक मानचित्रण माना जाता है। यूनिकोड उस धारणा 2 को तोड़ता है , इसलिए आप साधारण टेक्स्ट एल्गोरिदम के लिए भी सुरक्षित रूप से wchar_t का उपयोग नहीं कर सकते हैं।

इसका मतलब यह है कि पोर्टेबल सॉफ्टवेयर wchar_t का उपयोग स्थानों के बीच पाठ के लिए एक सामान्य प्रतिनिधित्व के रूप में या सरल पाठ एल्गोरिदम के उपयोग को सक्षम करने के लिए नहीं कर सकता है।

आज wchar_t का क्या उपयोग है?

ज्यादा नहीं, पोर्टेबल कोड के लिए वैसे भी। यदि __STDC_ISO_10646__परिभाषित किया गया है तो wchar_t के मान सभी स्थानों में समान मूल्यों के साथ सीधे यूनिकोड कोड पॉइंट का प्रतिनिधित्व करते हैं। इससे पहले बताए गए अंतर-स्थानीय रूपांतरणों को करना सुरक्षित हो जाता है। हालाँकि, आप केवल इस बात पर भरोसा नहीं कर सकते कि आप इस तरह से wchar_t का उपयोग कर सकते हैं क्योंकि, जबकि अधिकांश यूनिक्स प्लेटफ़ॉर्म इसे परिभाषित करते हैं, विंडोज तब भी नहीं करता है जब तक कि विंडोज सभी स्थानों में समान wchar_t लोकेल का उपयोग नहीं करता है।

Windows परिभाषित नहीं करता __STDC_ISO_10646__है क्योंकि Windows UTF-16 को अपने wchar_t एन्कोडिंग के रूप में उपयोग करता है, और क्योंकि UTF-16 U + FFFF से अधिक कोडपॉइंट्स का प्रतिनिधित्व करने के लिए सरोगेट जोड़े का उपयोग करता है, जिसका अर्थ है कि UTF-16 के लिए आवश्यकताओं को पूरा नहीं करता है __STDC_ISO_10646__

मंच के लिए विशिष्ट कोड wchar_t अधिक उपयोगी हो सकता है। यह अनिवार्य रूप से विंडोज पर आवश्यक है (उदाहरण के लिए, कुछ फाइलें केवल wchar_t फ़ाइलनाम का उपयोग किए बिना नहीं खोली जा सकती हैं), हालांकि विंडोज एकमात्र प्लेटफॉर्म है जहां यह सच है जहां तक ​​मुझे पता है (इसलिए शायद हम wchar_t को 'Windows_char_t' के रूप में सोच सकते हैं)।

Hindsight में wchar_t पाठ हैंडलिंग को सरल बनाने या स्थानीय स्वतंत्र पाठ के लिए भंडारण के रूप में स्पष्ट रूप से उपयोगी नहीं है। पोर्टेबल कोड को इन उद्देश्यों के लिए उपयोग करने का प्रयास नहीं करना चाहिए। गैर-पोर्टेबल कोड इसे केवल उपयोगी हो सकता है क्योंकि कुछ एपीआई को इसकी आवश्यकता होती है।

वैकल्पिक

मुझे जो विकल्प पसंद है, वह है यूटीएफ -8 एनकोडेड सी स्ट्रिंग्स का उपयोग करना, यहां तक ​​कि प्लेटफार्मों पर भी विशेष रूप से यूटीएफ -8 के लिए अनुकूल नहीं है।

इस तरह से एक पूरे प्लेटफॉर्म पर एक आम टेक्स्ट प्रतिनिधित्व का उपयोग करके पोर्टेबल कोड लिख सकता है, अपने इच्छित उद्देश्य के लिए मानक डेटाटिप्स का उपयोग कर सकता है, उन प्रकारों के लिए भाषा का समर्थन प्राप्त कर सकता है (जैसे स्ट्रिंग शाब्दिक, हालांकि कुछ संकलक के लिए इसे बनाने के लिए कुछ ट्रिक्स आवश्यक हैं), कुछ मानक पुस्तकालय समर्थन, डिबगर समर्थन (अधिक तरकीबें आवश्यक हो सकती हैं), आदि विस्तृत वर्णों के साथ यह सब प्राप्त करने के लिए आम तौर पर कठिन या असंभव है, और आपको विभिन्न प्लेटफार्मों पर अलग-अलग टुकड़े मिल सकते हैं।

एक बात यूटीएफ -8 प्रदान नहीं करता है, एएससीआईआई के साथ सरल पाठ एल्गोरिदम का उपयोग करने की क्षमता है। इसमें UTF-8 किसी भी अन्य यूनिकोड एन्कोडिंग से ज्यादा खराब नहीं है। वास्तव में इसे बेहतर माना जा सकता है क्योंकि UTF-8 में मल्टी-कोड यूनिट अभ्यावेदन अधिक सामान्य हैं और इसलिए कोड में ऐसे बग्स जो चर चर का प्रतिनिधित्व करते हैं, वर्णों के निरूपण की संभावना अधिक होती है और यदि आप UTF से चिपके रहते हैं, तो इसकी तुलना में यह निश्चित है -32 एनएफसी या एनएफकेसी के साथ।

कई प्लेटफ़ॉर्म यूटीएफ -8 का उपयोग उनके मूल चार एन्कोडिंग के रूप में करते हैं और कई कार्यक्रमों को किसी भी महत्वपूर्ण पाठ प्रसंस्करण की आवश्यकता नहीं होती है, और इसलिए उन प्लेटफार्मों पर एक अंतर्राष्ट्रीयकृत प्रोग्राम लिखना अंतर्राष्ट्रीयकरण पर विचार किए बिना कोड लिखने से थोड़ा अलग है। अधिक व्यापक रूप से पोर्टेबल कोड लिखना, या अन्य प्लेटफार्मों पर लिखना एपीआई की सीमाओं पर रूपांतरण डालने की आवश्यकता है जो अन्य एन्कोडिंग का उपयोग करते हैं।

कुछ सॉफ़्टवेयर द्वारा उपयोग किया जाने वाला एक अन्य विकल्प क्रॉस-प्लेटफ़ॉर्म प्रतिनिधित्व को चुनना है, जैसे कि अहस्ताक्षरित लघु सरणियों में UTF-16 डेटा रखना, और फिर सभी लाइब्रेरी समर्थन की आपूर्ति करना और बस भाषा समर्थन में लागत के साथ रहना, आदि।

C ++ 11 में wchar_t, char16_t और char32_t को अटेंडेंट लैंग्वेज / लाइब्रेरी फीचर्स के विकल्प के रूप में नए तरह के वाइड कैरेक्टर जोड़े गए हैं। ये वास्तव में UTF-16 और UTF-32 होने की गारंटी नहीं हैं, लेकिन मुझे नहीं लगता कि कोई भी बड़ा कार्यान्वयन किसी और चीज का उपयोग करेगा। C ++ 11 भी UTF-8 समर्थन में सुधार करता है, उदाहरण के लिए UTF-8 स्ट्रिंग शाब्दिक के साथ ताकि VC ++ को UTF-8 एन्कोडेड स्ट्रिंग्स के उत्पादन में ट्रिक करने के लिए आवश्यक नहीं होगा (हालांकि मैं u8उपसर्ग का उपयोग करने के बजाय ऐसा करना जारी रख सकता हूं ) ।

बचने के विकल्प

TCHAR: TCHAR प्राचीन विंडोज प्रोग्रामों को माइग्रेट करने के लिए है जो चर से लेकर wchar_t तक की विरासत को मानते हैं, और जब तक कि आपका प्रोग्राम कुछ पिछली सहस्राब्दी में नहीं लिखा जाता है, तब तक इसे भूल जाते हैं। यह पोर्टेबल नहीं है और स्वाभाविक रूप से इसके एन्कोडिंग और यहां तक ​​कि इसके डेटा प्रकार के बारे में अनिर्दिष्ट है, जिससे यह किसी भी गैर-टीसीएचटी एपीआई के साथ अनुपयोगी है। चूंकि इसका उद्देश्य wchar_t पर माइग्रेशन है, जो हमने ऊपर देखा है यह एक अच्छा विचार नहीं है, TCHAR का उपयोग करने में कोई मूल्य नहीं है।


1. ऐसे अक्षर जो wchar_t स्ट्रिंग्स में प्रतिनिधित्व करने योग्य हैं, लेकिन जो किसी भी लोकेल में समर्थित नहीं हैं, उन्हें एकल wchar_t मान के साथ प्रतिनिधित्व करने की आवश्यकता नहीं है। इसका मतलब है कि wchar_t कुछ वर्णों के लिए एक चर चौड़ाई एन्कोडिंग का उपयोग कर सकता है, wchar_t के इरादे का एक और स्पष्ट उल्लंघन। यद्यपि यह तर्कपूर्ण है कि एक चरित्र wchar_t द्वारा प्रतिनिधित्व किया जा रहा है, यह कहने के लिए पर्याप्त है कि स्थानीय उस चरित्र का 'समर्थन' करता है, जिस स्थिति में चर-चौड़ाई एन्कोडिंग कानूनी नहीं है और विंडो का यूटीएफ -16 गैर-अनुरूप है।

2. यूनिकोड कई वर्णों को कई कोड बिंदुओं के साथ प्रस्तुत करने की अनुमति देता है, जो चर चौड़ाई एन्कोडिंग के रूप में सरल पाठ एल्गोरिदम के लिए समान समस्याएं पैदा करता है। यहां तक ​​कि अगर एक कड़ाई से बना सामान्यीकरण बनाए रखता है, तो भी कुछ पात्रों को कई कोड बिंदुओं की आवश्यकता होती है। देखें: http://www.unicode.org/standard/where/


3
जोड़: utf8everywhere.org , Windows पर UTF-8 का उपयोग करने की अनुशंसा करता है और Boost.Nowide औपचारिक समीक्षा के लिए निर्धारित है।
याकॉव गल्का

2
सबसे अच्छी बात, ज़ाहिर है, विंडोज पर C # या VB.Net का उपयोग करना है :) या सादे पुराने C / Win32। लेकिन अगर आपको C ++ का उपयोग करना चाहिए, तो TCHAR जाने का सबसे अच्छा तरीका है। जो MSVS2005 और उच्चतर पर "wchar_t" को परिभाषित करता है। IMHO ...
paulm4

4
@BrendanMcK: ज़रूर, कोड जो विंडोज़ पर Win32 API और अन्य सिस्टम पर अन्य API का उपयोग करता है, मौजूद नहीं है। सही? Microsoft के दृष्टिकोण ("अपने ऐप में हर जगह आंतरिक रूप से उपयोग करें) के साथ समस्या यह है कि यहां तक ​​कि कोड को भी प्रभावित करता है जो सिस्टम को सीधे इंटरफ़ेस नहीं करता है और पोर्टेबल हो सकता है।
याकोव गल्का

4
समस्या आपको लगता है कि है है "ब्रेक" मानक सी (++) लाइब्रेरी एक एएनएसआई कोड पृष्ठ के रूप में क्योंकि माइक्रोसॉफ्ट के निर्णय समर्थन UTF-8 में नहीं विंडोज-विशिष्ट कार्यों का उपयोग करने के लिए। उदाहरण के लिए, आप fopenएक फ़ाइल नहीं रख सकते जिसका नाम गैर-एएनएसआई अक्षर है।
dan04

11
@ dan04 हां, आप विंडोज पर मानक पुस्तकालय का उपयोग नहीं कर सकते हैं, लेकिन आप एक पोर्टेबल इंटरफ़ेस बना सकते हैं जो अन्य प्लेटफार्मों पर मानक पुस्तकालय को लपेटता है और Win32 W फ़ंक्शन का उपयोग करने से पहले सीधे UTF-8 से wchar_t में कनवर्ट करता है।
bames53

20

Wchar_t के साथ "गलत" कुछ भी नहीं है। समस्या यह है कि, NT 3.x दिनों में वापस, Microsoft ने तय किया कि यूनिकोड अच्छा था (यह है), और यूनिकोड को 16-बिट, wchar_t वर्णों के रूप में लागू करना है। इसलिए 90 के दशक के मध्य से अधिकांश Microsoft साहित्य ने यूनिकोड == utf16 == wchar_t की बराबरी की।

जो, दुख की बात है, बिल्कुल भी नहीं है। "वाइड कैरेक्टर" सभी परिस्थितियों में, सभी प्लेटफार्मों पर आवश्यक रूप से 2 बाइट्स नहीं हैं ।

मैं: यह "यूनिकोड" (इस सवाल का स्वतंत्र, सी के स्वतंत्र ++) मैंने आज तक देखा पर सबसे अच्छा प्राइमरों में से एक है अत्यधिक यह सलाह देते हैं:

और मैं ईमानदारी से "8-बिट ASCII" बनाम "Win32 चौड़े अक्षर" बनाम "wchar_t-in-general" से निपटने का सबसे अच्छा तरीका मानता हूं कि बस "विंडोज अलग है" ... और तदनुसार कोड।

IMHO...

पुनश्च:

मैं पूरी तरह से ऊपर jamesdlin से सहमत हूँ:

विंडोज पर, आपके पास वास्तव में कोई विकल्प नहीं है। इसके आंतरिक API को UCS-2 के लिए डिज़ाइन किया गया था, जो उस समय से उचित था, जब यह चर-लंबाई UTF-8 और UTF-16 एन्कोडिंग के मानकीकृत होने से पहले था। लेकिन अब जब वे UTF-16 का समर्थन करते हैं, तो वे दोनों दुनिया के सबसे बुरे लोगों के साथ समाप्त हो गए हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.