2013-11-03 5 views
17

इंटरनेट पर कई पोस्ट हैं जो सुझाव देते हैं कि आपको std::vector<unsigned char> या बाइनरी डेटा के समान कुछ उपयोग करना चाहिए।क्या मैं सी ++ 11 में बाइनरी डेटा के लिए सुरक्षित रूप से std :: स्ट्रिंग का उपयोग कर सकता हूं?

लेकिन इसके लिए मैं std::basic_string संस्करण को अधिक पसंद करता हूं, क्योंकि यह कई सुविधाजनक स्ट्रिंग मैनिपुलेशन फ़ंक्शंस प्रदान करता है। और AFAIK, सी ++ 11 के बाद, मानक गारंटी देता है कि प्रत्येक ज्ञात सी ++ 03 कार्यान्वयन पहले से ही क्या करता है: std::basic_string इसकी सामग्री को स्मृति में संगत रूप से संग्रहीत करता है।

पहली नज़र में, std::basic_string<unsigned char> एक अच्छा विकल्प हो सकता है।

मैं std::basic_string<unsigned char> का उपयोग नहीं करना चाहता, हालांकि, लगभग सभी ऑपरेटिंग सिस्टम केवल char* स्वीकार करते हैं, जिससे एक स्पष्ट कलाकार आवश्यक होता है। इसके अलावा, स्ट्रिंग अक्षर const char* हैं, इसलिए मुझे हर बार जब मैंने बाइनरी स्ट्रिंग को स्ट्रिंग अक्षर दिया था, तो मुझे const unsigned char* पर एक स्पष्ट कलाकार की आवश्यकता होगी, जिसे मैं टालना चाहूंगा। साथ ही, फाइलों या नेटवर्किंग बफर से पढ़ने और लिखने के लिए कार्य समान रूप से char* और const char* पॉइंटर्स स्वीकार करते हैं।

यह std::string छोड़ देता है, जो मूल रूप से std::basic_string<char> के लिए टाइप किया गया है।

द्विआधारी डेटा के लिए std::string का उपयोग करने वाला एकमात्र संभावित शेष मुद्दा (जिसे मैं देख सकता हूं) std::stringchar (जिसे हस्ताक्षर किया जा सकता है) का उपयोग करता है।

char, signed char, और unsigned char तीन विभिन्न प्रकार हैं और char या तो अहस्ताक्षरित या हस्ताक्षर किए जा सकता है।

तो, जब 11111111b का एक वास्तविक बाइट मूल्य std::string:operator[] चार के रूप में से दिया जाता है, और आप अपने मूल्य जाँच करना चाहते हैं, अपने मूल्य किया जा सकता है या तो 255 (यदि char अहस्ताक्षरित है) या यह "कुछ नकारात्मक" हो सकता है (अगर char आपके नंबर के प्रतिनिधित्व के आधार पर हस्ताक्षरित है)।

इसी प्रकार, यदि आप स्पष्ट रूप से एक std::string करने के लिए वास्तविक बाइट मूल्य 11111111b संलग्न करना चाहते हैं, बस जोड़कर (char) (255) कार्यान्वयन से परिभाषित (और यहां तक ​​कि एक संकेत उठाना) यदि char हस्ताक्षरित किया गया है और हो सकता है एक अतिप्रवाह में intchar को बातचीत के परिणाम ।

तो, क्या इसके आसपास एक सुरक्षित तरीका है, जो std::string बाइनरी-सुरक्षित बनाता है?

§3.10/15 राज्यों:

एक कार्यक्रम निम्नलिखित प्रकार व्यवहार अपरिभाषित है में से एक के अलावा अन्य के glvalue के माध्यम से एक वस्तु की संग्रहीत मूल्य तक पहुँचने के लिए प्रयास करता है:

  • [...]
  • एक प्रकार है कि हस्ताक्षर किए या अहस्ताक्षरित प्रकार वस्तु के गतिशील प्रकार के अनुरूप,
  • [...]
  • एक चार या हस्ताक्षरित चार प्रकार।

अगर मैं इसे सही ढंग से समझ, उपयोग और std::string की सामग्री में हेरफेर करने के unsigned char* सूचक का उपयोग कर अनुमति देने के लिए लगता है और यह भी अच्छी तरह से परिभाषित बनाता कौन सा,। यह सिर्फ , एक unsigned char रूप बिट पैटर्न reinterprets, किसी भी बदलाव या जानकारी हानि के बिना उत्तरार्द्ध अर्थात् क्योंकि में एक char, signed char, और unsigned char मूल्य प्रतिनिधित्व के लिए इस्तेमाल किया जाना चाहिए सभी बिट्स।

मैं तो char ही की signedness की [0, 255] रेंज में उपयोग करने के लिए और परिवर्तन बाइट मूल्यों, एक अच्छी तरह से परिभाषित और पोर्टेबल ढंग से, चाहे एक साधन के रूप std::string की सामग्री के इस unsigned char* व्याख्या इस्तेमाल कर सकते हैं।

यह संभावित रूप से हस्ताक्षरित char से उत्पन्न होने वाली किसी भी समस्या का समाधान करना चाहिए।

क्या मेरी धारणाएं और निष्कर्ष सही हैं?

इसके अलावा, unsigned char* समान पैटर्न की व्याख्या (यानी 11111111b या 10101010b) सभी कार्यान्वयन पर समान होने की गारंटी है? अलग-अलग रखें, क्या मानक गारंटी है कि "unsigned char की आंखों को देखकर", वही बिट पैटर्न हमेशा एक ही संख्यात्मक मान की ओर जाता है (मानते हैं कि बाइट में बिट्स की संख्या समान है)?

कर सकते हैं मैं इस प्रकार सुरक्षित रूप से (अर्थात, के बिना किसी भी अपरिभाषित या कार्यान्वयन से परिभाषित व्यवहार) सी ++ 11 में भंडारण और बाइनरी डेटा जोड़ तोड़ के लिए std::string का उपयोग करें?

+0

जब आप लिखते हैं, "लगभग सभी मानक लाइब्रेरी फ़ंक्शन केवल char * स्वीकार करते हैं," क्या आप समझा सकते हैं कि आप कौन से लाइब्रेरी फ़ंक्शंस का उपयोग करना चाहते हैं? यदि आप सी ++ मानक लाइब्रेरी से चिपके रहते हैं, तो 'std :: basic_string ' सदस्य फ़ंक्शंस आपके द्वारा प्रदान किए जाने वाले वास्तविक 'CharT' प्रकार को प्रतिबिंबित करेगा। उदाहरण: 'std :: basic_string :: c_str()' रिटर्न 'कॉन्स्टिनेटेड char *'। आईओ के संदर्भ में, यदि आप 'हस्ताक्षरित चार' पर एक आईट्रीम या ओस्ट्रीम टेम्पलेट कर सकते हैं, तो सब कुछ अंतःक्रिया करेगा। – NicholasM

+0

आप केवल 'std :: basic_string ' का व्युत्पन्न वर्ग बना सकते हैं और इसके लिए कुछ अंतर्निहित बना सकते हैं। – Zaffy

+5

बस एक वेक्टर का उपयोग करें। आप इसके साथ कुछ भी कर सकते हैं कि आप एक स्ट्रिंग के साथ कर सकते हैं। – jrok

उत्तर

17

रूपांतरण static_cast<char>(uc) जहां uc प्रकार का है unsigned char है हमेशा मान्य है: 3.9.1 के अनुसार [basic.fundamental] char, signed char, और unsigned char के प्रतिनिधित्व char दो अन्य प्रकार से एक के लिए समान होने के साथ समान हैं :

अक्षरों (चार) के रूप में घोषित ऑब्जेक्ट्स कार्यान्वयन के मूल चरित्र सेट के किसी भी सदस्य को स्टोर करने के लिए पर्याप्त होंगे। यदि इस सेट का कोई चरित्र किसी वर्ण ऑब्जेक्ट में संग्रहीत होता है, तो उस वर्ण ऑब्जेक्ट का अभिन्न मान उस वर्ण के एकल वर्ण शाब्दिक रूप के मान के बराबर होता है। यह क्रियान्वयन-परिभाषित है कि क्या एक चार वस्तु नकारात्मक मान रख सकती है। अक्षरों को स्पष्ट रूप से हस्ताक्षरित या हस्ताक्षरित घोषित किया जा सकता है। सादा चार, हस्ताक्षरित चार, और हस्ताक्षरित चार तीन अलग-अलग प्रकार होते हैं, जिन्हें सामूहिक रूप से संकीर्ण चरित्र प्रकार कहा जाता है। एक चार, एक हस्ताक्षरित चार, और एक हस्ताक्षरित चार समान भंडारण पर कब्जा करते हैं और एक ही संरेखण आवश्यकताओं (3.11) है; यानी, उनके पास एक ही वस्तु का प्रतिनिधित्व है। संकीर्ण चरित्र प्रकारों के लिए, वस्तु प्रतिनिधित्व के सभी बिट्स मूल्य प्रतिनिधित्व में भाग लेते हैं। हस्ताक्षरित संकीर्ण चरित्र प्रकारों के लिए, मूल्य प्रतिनिधित्व के सभी संभावित बिट पैटर्न संख्याओं का प्रतिनिधित्व करते हैं। ये आवश्यकताएं अन्य प्रकारों के लिए नहीं हैं। किसी भी विशेष कार्यान्वयन में, एक सादा चार वस्तु एक ही मानों को एक हस्ताक्षरित चार या हस्ताक्षरित चार के रूप में ले सकती है; कौन सा कार्यान्वयन-परिभाषित है।

char को unsigned char की श्रेणी से बाहर मान परिवर्तित होगा, ज़ाहिर है, समस्याग्रस्त हो और अपरिभाषित व्यवहार हो सकता है। यही है, जब तक आप मज़ेदार मानों को std::string में संग्रहीत करने की कोशिश नहीं करते हैं, तो आप ठीक होंगे। बिट पैटर्न के संबंध में, आप n वें बिट पर भरोसा कर सकते हैं ताकि 2 n में अनुवाद किया जा सके। ध्यान से संसाधित होने पर std::string में बाइनरी डेटा स्टोर करने में कोई समस्या नहीं होनी चाहिए।

उस ने कहा, मैं आपके आधार पर नहीं खरीदता: प्रसंस्करण बाइनरी डेटा को ज्यादातर बाइट्स से निपटने की आवश्यकता होती है जो unsigned मानों का उपयोग करके सर्वोत्तम तरीके से छेड़छाड़ की जाती है। char* और unsigned char* के बीच आपको कुछ मामलों को कन्वर्ट करने की आवश्यकता होगी, जब char के उपयोग को गड़बड़ करते समय स्पष्ट रूप से इलाज नहीं किया गया है तो त्रुटिपूर्ण रूप से चुप रहेंगे! यही है, unsigned char से निपटने से त्रुटियों को रोका जा सकेगा। मैं इस आधार पर भी खरीद नहीं करता कि आपको उन सभी अच्छे स्ट्रिंग फ़ंक्शंस मिलते हैं: एक के लिए, आप आमतौर पर एल्गोरिदम का उपयोग करना बंद कर देते हैं लेकिन बाइनरी डेटा स्ट्रिंग डेटा नहीं है। संक्षेप में: std::vector<unsigned char> के लिए सिफारिश सिर्फ पतली हवा से बाहर नहीं आ रही है! डिजाइन में जाल खोजने के लिए कड़ी मेहनत से बचने के लिए जानबूझकर जानबूझकर है!

#include <cstddef> 
unsigned char const* operator""_u (char const* s, size_t) 
{ 
    return reinterpret_cast<unsigned char const*>(s); 
} 

unsigned char const* hello = "hello"_u; 
+0

आपके विस्तृत उत्तर के लिए धन्यवाद। आपके तर्क बहुत ही भरोसेमंद हैं। मुझे यकीन नहीं है कि मैं अभी तक उद्धृत पैराग्राफ को पूरी तरह से समझता हूं, इसलिए कृपया मेरे पूछने के साथ नंगे: 1) यदि मैं यूजर-डिफ़ाइंड स्ट्रिंग अक्षर का उपयोग करता हूं तो आपने यूयूएफ -8 स्ट्रिंग के साथ एक साथ प्रदान किया है जिसमें 127 से अधिक कोड पॉइंट हैं, जैसे u8 "â" _u, जो बाइट अनुक्रम 0xC3 0xA2 है, और मेरे चार पर हस्ताक्षर किए जाते हैं, इसके परिणामस्वरूप उस स्ट्रिंग के दोनों वर्ण रूपांतरण से पहले नकारात्मक हो जाएंगे। क्या मानक गारंटी है कि आपका कनवर्टिंग शाब्दिक हमेशा एक ही हस्ताक्षरित चार संख्यात्मक मानों का परिणाम देगा ... – JohnCand

+0

... (यानी क्या मुझे हमेशा संख्यात्मक मान 0xC3 0xA2 वापस मिल जाएगा)? 2) मैं ओएस फ़ंक्शंस के साथ सही तरीके से इंटरफ़ेस कैसे करूं जो केवल char * या const char * स्वीकार करते हैं? आप शायद अपने उत्तर में दोनों प्रश्नों पर पहले से ही छू चुके हैं, लेकिन वे बिंदु अभी भी मेरे लिए पूरी तरह से स्पष्ट नहीं हैं। – JohnCand

+3

@ जॉनकाक 2: 1. 'हस्ताक्षरित चार' और 'हस्ताक्षरित चार' के प्रतिनिधित्व बिट्स को बदले बिना एक दूसरे के बीच डाला जा सकता है। अपशॉट यह है कि सकारात्मक 'हस्ताक्षरित char' मानों के समान' मानदंड वाले चार 'के समान मूल्य होगा; ऋणात्मक मान कैसे 'हस्ताक्षरित चार' में परिवर्तित होते हैं या आसपास के दूसरे तरीके को निर्दिष्ट नहीं किया जाता है लेकिन बिट पैटर्न अभी भी नहीं बदलता है। यह 'हस्ताक्षरित चार' को 'हस्ताक्षरित चार' में परिवर्तित कर रहा है और पीछे पहचान फ़ंक्शन (इसी प्रकार दूसरी तरफ) है। 2. 'reinterpret_cast (...)'। मुद्दा यह है कि संकलक कैच करता है जहां इसकी आवश्यकता होती है। –

1

हां आपकी धारणाएं सही हैं। std :: स्ट्रिंग में हस्ताक्षरित char के अनुक्रम के रूप में बाइनरी डेटा स्टोर करें।

+3

मैं डाउनवॉटिंग से बचना होगा। लेकिन कैनोलिक जवाब में 'हस्ताक्षर किए गए' और 'वेक्टर' शब्द – sehe

+0

शामिल होना चाहिए, मुझे लगता है कि यह डाउनवोट को समझाने में मददगार होगा और कुछ तर्क दे रहा है कि यह क्यों बुरा है। – Venemo

-1

मैं:

केवल char का उपयोग कर स्ट्रिंग शाब्दिक के बारे में एक हो सकता है लेकिन फिर भी यह है कि उपयोगकर्ता परिभाषित स्ट्रिंग सी ++ 11 में शुरू की शाब्दिक के साथ पानी नहीं रखता है के पक्ष में हल्का उचित तर्क माइक्रोसॉफ्ट विजुअल स्टूडियो में बाइनरी डेटा को संभालने के लिए std :: स्ट्रिंग का उपयोग कर परेशानी में भाग लिया है। मैंने देखा है कि तारों को निष्पक्ष रूप से छोटा कर दिया गया है, इसलिए मानकों के दस्तावेजों के बारे में इस पर ध्यान दिए बिना मैं ऐसा नहीं करूँगा।

+2

"मानक मानकों के कहने के बावजूद" कह रहे हैं "शैतानवाद की तरह है: डी –

संबंधित मुद्दे

 संबंधित मुद्दे