2012-12-21 26 views
17

हम को परिवर्तित करके T के किसी ऑब्जेक्ट का प्रतिनिधित्व देख सकते हैं जो उस ऑब्जेक्ट को char* में इंगित करता है। व्यवहार में कम से कम: ff 01 00 00:चार सूचक को कब और कैसे रूपांतरण की अनुमति है?

int x = 511; 
unsigned char* cp = (unsigned char*)&x; 
std::cout << std::hex << std::setfill('0'); 
for (int i = 0; i < sizeof(int); i++) { 
    std::cout << std::setw(2) << (int)cp[i] << ' '; 
} 

यह मेरा प्रणाली पर 511 के प्रतिनिधित्व आउटपुट।

(निश्चित रूप से) कुछ कार्यान्वयन परिभाषित व्यवहार यहां होता है। कौन से कास्ट मुझे int* को unsigned char* में परिवर्तित करने की अनुमति दे रहे हैं और कौन से रूपांतरण उस कलाकार को लागू करते हैं? क्या मैं जल्द से जल्द अपरिभाषित व्यवहार का आह्वान कर रहा हूं? क्या मैं इस तरह के T* टाइप कर सकता हूं? ऐसा करने पर मैं भरोसा कैसे कर सकता हूं?

+3

मैं इसे अपरिभाषित व्यवहार है नहीं लगता है, कम से कम यदि आप डेटा को संशोधित नहीं करते हैं।लेकिन परिणाम इस बात पर निर्भर करेगा कि क्या आप प्लेटफॉर्म छोटा या बड़ा एंडियन है या नहीं। – Synxis

+2

ध्यान दें कि यह केवल 'char *' के लिए सुरक्षित है। विभिन्न प्रकार के रूप में पढ़ने के लिए पॉइंटर्स कास्टिंग * एलियासिंग * के साथ समस्याएं पैदा करता है। सी और सी ++ भाषाएं संकलक को गारंटी देती हैं कि विभिन्न प्रकार के पॉइंटर्स कभी भी एक ही ऑब्जेक्ट को इंगित नहीं कर सकते हैं, इसलिए ऑप्टिमाइज़र एक रजिस्टर में मूल्य को स्टोर करने या लोड को उठाने या लूप से लिखने जैसी चीज़ें कर सकता है। 'char *' एकमात्र अपवाद है। डिस्क और नेटवर्क बफर से और से क्रमबद्ध करने के कारण, 'char *' को किसी भी चीज़ के साथ उपनाम माना जाना चाहिए। –

+2

@ZanLynx - पुनः "' char * 'एकमात्र अपवाद है": बिल्कुल नहीं। मानक 'हस्ताक्षरित चार *' में रूपांतरण की अनुमति भी देता है। –

उत्तर

12

कौन से कास्ट मुझे int* को unsigned char* में परिवर्तित करने की अनुमति दे रहा है?

इस मामले में सी-शैली कास्ट reinterpret_cast<unsigned char*> जैसा ही है।

क्या मैं इस तरह कोई टी * प्रकार डाल सकता हूं?

हां और नहीं। हां भाग: आप किसी भी सूचक प्रकार को char* या unsigned char* (उपयुक्त const और/या volatile क्वालीफायर के साथ) सुरक्षित रूप से डाल सकते हैं। नतीजा कार्यान्वयन-परिभाषित है, लेकिन यह कानूनी है।

कोई भाग नहीं: मानक स्पष्ट रूप से char* और unsigned char* को लक्ष्य प्रकार के रूप में अनुमति देता है। हालांकि, आप (उदाहरण के लिए) double* को int* पर सुरक्षित रूप से नहीं डाल सकते हैं। ऐसा करें और आपने कार्यान्वयन-परिभाषित व्यवहार से अपरिभाषित व्यवहार तक सीमा पार कर ली है। यह सख्त एलियासिंग नियम का उल्लंघन करता है।

+1

आह, तो ऐसा लगता है कि (जीनबुशुएव और @ नोबर के उत्तरों से) 'टी *' से किसी भी 'यू *' में कास्ट अनिर्दिष्ट परिणाम है (लेकिन होगा ठीक है अगर मैं दोबारा वापस आ गया) और अगर मुझे कुछ भी 'चार *' या 'हस्ताक्षरित चार *' के अलावा डाला गया था और तब * ऑब्जेक्ट * ऑब्जेक्ट * पॉइंटर के रूप में, मुझे अपरिभाषित व्यवहार (सख्त एलियासिंग के अनुसार) होगा। सही उत्तर में इन दोनों बिंदुओं का होगा। ;) –

2

आपके उदाहरण में कार्यान्वयन व्यवहार आपके सिस्टम की एंडियननेस विशेषता है, इस मामले में आपका सीपीयू थोड़ा एंडियन है।
टाइपिंग कास्टिंग के बारे में, जब आप int* से char* पर डालते हैं तो आप जो कुछ भी कर रहे हैं, उसे संकलित करने के लिए संकलक बता रहा है कि cp एक चार के रूप में इंगित कर रहा है, इसलिए यह केवल पहले बाइट को पढ़ेगा और इसे एक चरित्र के रूप में व्याख्या करेगा।

5

आपका कलाकारों को नक्शे:

unsigned char* cp = reinterpret_cast<unsigned char*>(&x); 

एक int की अंतर्निहित प्रतिनिधित्व कार्यान्वयन परिभाषित है, और यह देखने के रूप में वर्ण आपको लगता है कि जांच करने के लिए अनुमति देता है। आपके मामले में, यह 32-बिट थोड़ा एंडियन है।

यहां कुछ भी खास नहीं है - आंतरिक प्रतिनिधित्व की जांच करने की यह विधि किसी भी डेटा प्रकार के लिए मान्य है।

सी ++ 03 5.2.10.7: किसी ऑब्जेक्ट के लिए पॉइंटर को अलग-अलग प्रकार के ऑब्जेक्ट में स्पष्ट रूप से पॉइंटर में परिवर्तित किया जा सकता है। सिवाय इसके कि "पॉइंटर टू टी 1" के प्रकार के रूप में "पॉइंटर टू टी 2" (जहां टी 1 और टी 2 ऑब्जेक्ट प्रकार हैं और जहां टी 2 की संरेखण आवश्यकताएं टी 1 की तुलना में कोई कठोर नहीं हैं) और उसके मूल प्रकार की उपज पर वापस जाएं मूल सूचक मूल्य, ऐसे सूचक रूपांतरण का परिणाम अनिर्दिष्ट है।

यह बताता है कि कास्ट परिणाम अनिर्दिष्ट व्यवहार में परिणाम। लेकिन व्यावहारिक रूप से बोलते हुए, किसी भी सूचक प्रकार से char* तक कास्टिंग आपको हमेशा संदर्भित वस्तु के आंतरिक प्रतिनिधित्व की जांच (और संशोधित) करने की अनुमति देगा।

+0

कड़ाई से बोलते हुए, मानक गारंटी नहीं देता है कि 'char'' int 'से छोटा है। – nobar

+2

"सख्त एलियासिंग नियम" के लिए प्रासंगिक मानकों को यहां प्रदान किया गया है: http://stackoverflow.com/a/7005988/86967। सारांश: यदि आप 'char * 'या' unsigned char * 'के माध्यम से ऑब्जेक्ट तक पहुंचते हैं, तो कोई समस्या नहीं है। – nobar

+0

यह बेहद स्पर्शपूर्ण है, लेकिन यह ध्यान रखना दिलचस्प है कि _strict aliasing rule_ बताता है कि 'char *' का उपयोग अनुकूलन में हस्तक्षेप कर सकता है। यह वह जगह है जहां [गैर-मानक] (http://stackoverflow.com/questions/6434549/does-c11-add-the-c99-restrict-specifier-if-not-why-not) 'प्रतिबंधित' कीवर्ड हो सकता है उपयोगी - हालांकि यह हाथ पर सवाल पर लागू नहीं होता है, क्योंकि _aliasing_ वास्तव में दिए गए प्रश्न का बिंदु है। – nobar

1

पॉइंटर्स के बीच कास्ट स्वयं हमेशा संभव होता है क्योंकि सभी पॉइंटर्स स्मृति पते से अधिक कुछ नहीं हैं और स्मृति में, जो कुछ भी, स्मृति में हमेशा बाइट्स के अनुक्रम के रूप में सोचा जा सकता है।

लेकिन - निश्चित रूप से अनुक्रम का गठन जिस तरह से स्मृति में विघटित प्रकार का प्रतिनिधित्व किया जाता है, और यह सी ++ विनिर्देशों के दायरे से बाहर है।

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

आम तौर पर एक चीज से बचने के लिए टाइप आकारों के बीच संबंध को पूर्वनिर्धारित करना है: अपने नमूने में sizeof(int) == 4*sizeof(char): यह हमेशा जरूरी नहीं है।

लेकिन यह हमेशा सच है कि sizeof (टी) = एन * sizeof (चार), इसलिए जो कुछ भी टी हमेशा की चार-रों

+0

मुझे याद आ रही है कि ओपी ने माना कि 'sizeof (int) == 4 * sizeof (char) '। – phonetagger

+0

@phonetagger एमिलियो मेरे प्रश्न के मूल संस्करण का उत्तर दे रहा है जो कि '4 * आकार (char)' पर निर्भर था। –

+0

@sftrabbit - ठीक है। लेकिन अपनी टिप्पणी को हटाएं "हटाने की कोई ज़रूरत नहीं है ..." – phonetagger

0

जब तक आप एक डाली ऑपरेटर है, तो एक एक पूर्णांक संख्या के रूप में देखा जा सकता है कास्ट बस उस स्मृति क्षेत्र को एक अलग तरीके से "देखने" के लिए कह रहा है। कुछ भी वास्तव में कल्पना नहीं, मैं कहूंगा।

फिर, आप स्मृति क्षेत्र बाइट-बाय-बाइट पढ़ रहे हैं; जब तक आप इसे नहीं बदलते, यह ठीक है। बेशक, जो आप देखते हैं उसका नतीजा मंच से बहुत निर्भर करता है: अंतहीनता, शब्द का आकार, पैडिंग आदि के बारे में सोचें।

0

बस बाइट क्रम तो रिवर्स यह

00 00 01 ff 

कौन सा 256 (01) + 255 (एफएफ) = 511

इसका कारण यह है अपने platfom थोड़ा endian है है हो जाता है।

3

इस मामले में सी-शैली कास्ट reinterpret_cast के बराबर है। मानक 5.2.10 में अर्थशास्त्र का वर्णन करता है। विशेष रूप से, पैरा 7 में:

"एक वस्तु के लिए एक सूचक स्पष्ट रूप से एक सूचक के लिए एक अलग वस्तु type.70 में बदला जा सकता जब प्रकार का एक prvalue वी" टी 1 करने के लिए सूचक " प्रकार में बदल जाती है "cvT2 सूचक", परिणाम static_cast<cvT2*>(static_cast<cvvoid*>(v)) है अगर दोनों T1 और टी 2 मानक लेआउट प्रकार (3.9) और टी 2 के संरेखण आवश्यकताओं रहे हैं कोई टी 1 के से अधिक सख्त। प्रकार का एक prvalue परिवर्तित " T1 के सूचक "टाइप टू पॉइंटर टू टी 2" (जहां टी 1 और टी 2 ऑब्जेक्ट प्रकार और हैं जहां टी 2 की संरेखण आवश्यकताओंकी तुलना में कोई कठोर नहीं है 210 टी 1) और उसके मूल प्रकार पर वापस मूल सूचक मूल्य उत्पन्न करता है। किसी अन्य तरह के सूचक रूपांतरण के परिणाम अनिर्दिष्ट है। "

यह आपके मामले में इसका क्या मतलब है, संरेखण आवश्यकताओं को संतुष्ट कर रहे हैं, और परिणाम अनिर्दिष्ट है।

+0

आह, तो यह केवल तभी परिभाषित होता है जब आप 'टी *' से 'यू *' तक और 'टी * 'पर वापस आते हैं? '' * * को ''* * पर कास्ट करने का नतीजा केवल निर्दिष्ट नहीं है? अहा। –

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

  • कोई संबंधित समस्या नहीं^_^