पुन: उपयोग कैसे करें?


459

मैं reinterpret_castबनाम की प्रयोज्यता से थोड़ा भ्रमित हूं static_cast। जब मैंने सामान्य नियमों को पढ़ा है, तब से स्टेटिक कास्ट का उपयोग किया जाता है जब संकलन समय पर व्याख्या की जा सकती है इसलिए शब्द static। यह वह C है जो C ++ कंपाइलर आंतरिक रूप से निहित कास्ट के लिए भी उपयोग करता है।

reinterpret_casts दो परिदृश्यों में लागू होते हैं:

  • पूर्णांक प्रकारों को सूचक प्रकारों में परिवर्तित करें और इसके विपरीत
  • एक सूचक प्रकार को दूसरे में बदलें। मुझे जो सामान्य विचार मिलता है, वह अप्रमाणिक है और इसे टाला जाना चाहिए।

जहाँ मैं थोड़ा उलझन में हूँ एक उपयोग है जिसकी मुझे आवश्यकता है, मैं C ++ को C से कॉल कर रहा हूँ और C कोड को C ++ ऑब्जेक्ट पर रखने की आवश्यकता है, इसलिए मूल रूप से यह एक है void*void *वर्ग और वर्ग प्रकार के बीच कनवर्ट करने के लिए किस कास्ट का उपयोग किया जाना चाहिए ?

मैंने दोनों का उपयोग देखा है static_castऔर reinterpret_cast? यद्यपि मैं जो पढ़ रहा हूं, उससे यह प्रतीत होता है staticकि बेहतर है क्योंकि कलाकारों का संकलन समय पर हो सकता है? हालांकि यह reinterpret_castएक पॉइंटर प्रकार से दूसरे में बदलने के लिए उपयोग करने के लिए कहता है ?


9
reinterpret_castरन टाइम पर नहीं होता है। वे दोनों संकलन-समय कथन हैं। से en.cppreference.com/w/cpp/language/reinterpret_cast : "विपरीत static_cast, लेकिन const_cast की तरह, reinterpret_cast अभिव्यक्ति किसी भी सीपीयू निर्देशों के संकलन नहीं है यह पूरी तरह एक संकलक निर्देश जो संकलक का निर्देश बिट्स के अनुक्रम के इलाज के लिए है। अभिव्यक्ति के (ऑब्जेक्ट प्रतिनिधित्व) के रूप में अगर यह new_type था। "
क्राइस लुआंगो

@HeretoLearn, क्या प्रासंगिक कोड टुकड़ों को * .c और * .cpp फ़ाइल से जोड़ना संभव है? मुझे लगता है कि यह प्रश्न के विस्तार में सुधार कर सकता है।
ओरेनइशालोम

जवाबों:


442

C ++ मानक निम्नलिखित की गारंटी देता है:

static_castvoid*पते को सुरक्षित रखने के लिए और उसके पास एक सूचक रखें। अर्थात्, निम्नलिखित में a, bऔर cसभी एक ही पते पर इंगित करते हैं:

int* a = new int();
void* b = static_cast<void*>(a);
int* c = static_cast<int*>(b);

reinterpret_castकेवल इस बात की गारंटी देता है कि यदि आप एक अलग प्रकार के लिए एक सूचक डालते हैं, और फिर reinterpret_castयह मूल प्रकार पर वापस जाता है , तो आपको मूल मूल्य मिलता है। तो निम्नलिखित में:

int* a = new int();
void* b = reinterpret_cast<void*>(a);
int* c = reinterpret_cast<int*>(b);

aऔर cइसमें समान मूल्य होते हैं, लेकिन इसका मूल्य bअनिर्दिष्ट होता है। (व्यवहार में यह आम तौर पर समान पते के रूप में aऔर होगा c, लेकिन यह मानक में निर्दिष्ट नहीं है, और यह अधिक जटिल मेमोरी सिस्टम वाली मशीनों पर सच नहीं हो सकता है।)

और से कास्टिंग के लिए void*, static_castप्राथमिकता दी जानी चाहिए।


18
मुझे यह तथ्य पसंद है कि 'b' अपरिभाषित है। यह आपके साथ मूर्खतापूर्ण चीजें करना बंद कर देता है। यदि आप किसी अन्य पॉइंटर प्रकार पर कुछ डालते हैं, तो आप समस्याओं के बारे में पूछ रहे हैं और इस तथ्य पर कि आप उस पर निर्भर नहीं रह सकते, आपको अधिक सावधान करता है। यदि आपने static_cast <> का उपयोग किया था, तो वैसे भी 'b' किस उपयोग का है?
मार्टिन यॉर्क

3
मुझे लगा कि पुन: व्याख्या_कास्ट <> समान बिट पैटर्न की गारंटी देता है। (जो एक अन्य प्रकार के लिए एक वैध सूचक के समान नहीं है)।
मार्टिन यॉर्क

37
bउपयोग करते समय C ++ 11 में अब का मान अनिर्दिष्ट नहीं है reinterpret_cast। और C ++ 03 में कास्ट के साथ int*करने के लिए void*मना किया गया था reinterpret_cast(हालांकि कंपाइलरों ने इसे लागू नहीं किया था और यह अव्यावहारिक था, इसलिए C ++ 11 के लिए बदल दिया गया था)।
जोहान्स शाउब -

55
यह वास्तव में "जब reinterpret_cast का उपयोग करने के लिए" के प्रश्न का उत्तर नहीं देता है।
ईनपोकलम

6
@LokiAstari मुझे लगता है कि अनिर्दिष्ट आपको मूर्खतापूर्ण काम करने से नहीं रोकता है। जब आपको याद हो कि यह अनिर्दिष्ट है, तो यह आपको रोक देता है। बहुत बड़ा फर्क। व्यक्तिगत रूप से मुझे अनिर्दिष्ट नहीं पसंद है। बहुत याद करना।
हेलिन वांग

158

एक मामला जब reinterpret_castआवश्यक होता है, जब अपारदर्शी डेटा प्रकारों के साथ हस्तक्षेप होता है। यह वेंडर एपीआई में अक्सर होता है, जिस पर प्रोग्रामर का कोई नियंत्रण नहीं है। यहां एक वंचित उदाहरण है जहां एक विक्रेता मनमाना वैश्विक डेटा संग्रहीत और पुनर्प्राप्त करने के लिए एक एपीआई प्रदान करता है:

// vendor.hpp
typedef struct _Opaque * VendorGlobalUserData;
void VendorSetUserData(VendorGlobalUserData p);
VendorGlobalUserData VendorGetUserData();

इस API का उपयोग करने के लिए, प्रोग्रामर को अपना डेटा VendorGlobalUserDataफिर से और वापस भेजना होगा। static_castकाम नहीं करेगा, एक का उपयोग करना चाहिए reinterpret_cast:

// main.cpp
#include "vendor.hpp"
#include <iostream>
using namespace std;

struct MyUserData {
    MyUserData() : m(42) {}
    int m;
};

int main() {
    MyUserData u;

        // store global data
    VendorGlobalUserData d1;
//  d1 = &u;                                          // compile error
//  d1 = static_cast<VendorGlobalUserData>(&u);       // compile error
    d1 = reinterpret_cast<VendorGlobalUserData>(&u);  // ok
    VendorSetUserData(d1);

        // do other stuff...

        // retrieve global data
    VendorGlobalUserData d2 = VendorGetUserData();
    MyUserData * p = 0;
//  p = d2;                                           // compile error
//  p = static_cast<MyUserData *>(d2);                // compile error
    p = reinterpret_cast<MyUserData *>(d2);           // ok

    if (p) { cout << p->m << endl; }
    return 0;
}

नीचे नमूना एपीआई के एक वंचित कार्यान्वयन है:

// vendor.cpp
static VendorGlobalUserData g = 0;
void VendorSetUserData(VendorGlobalUserData p) { g = p; }
VendorGlobalUserData VendorGetUserData() { return g; }

7
हां, यह केवल पुनर्परिभाषित_कास्ट के सार्थक उपयोग के बारे में है जिसके बारे में मैं सोच सकता हूं।
जफ

8
यह एक देर से सवाल हो सकता है, लेकिन विक्रेता एपीआई इसके लिए उपयोग क्यों नहीं करता void*है?
Xeo

19
@ Xeo वे शून्य का उपयोग नहीं करते हैं * क्योंकि तब वे संकलन समय पर (कुछ) टाइप-चेक खो देते हैं।
jesup

4
"अपारदर्शी" डेटा प्रकारों का एक व्यावहारिक उपयोग मामला है जब आप एक एपीआई को सी में उजागर करना चाहते हैं लेकिन सी ++ में कार्यान्वयन लिखते हैं। ICU एक पुस्तकालय का एक उदाहरण है जो कई स्थानों पर ऐसा करता है। उदाहरण के लिए, स्पूफ चेकर एपीआई में, आप प्रकार के पॉइंटर्स से निपटते हैं USpoofChecker*, जहां USpoofCheckerएक खाली संरचना है। हालांकि, हुड के तहत, जब भी आप पास करते हैं USpoofChecker*, तो यह reinterpret_castआंतरिक C ++ प्रकार से गुजरता है।
sffc

@sffc उपयोगकर्ता को C संरचना प्रकार उजागर क्यों नहीं कर रहा है?
गुप्त

101

संक्षिप्त उत्तर: यदि आप नहीं जानते कि इसका क्या reinterpret_castमतलब है, इसका उपयोग न करें। यदि आपको भविष्य में इसकी आवश्यकता होगी, तो आपको पता चल जाएगा।

पूर्ण उत्तर:

आइए बुनियादी संख्या प्रकारों पर विचार करें।

जब आप अपने प्रोसेसर के लिए उदाहरण के int(12)लिए परिवर्तित unsigned float (12.0f)करते हैं तो कुछ गणनाओं को लागू करने की आवश्यकता होती है क्योंकि दोनों संख्याओं में अलग-अलग बिट प्रतिनिधित्व होता है। यह वही static_castहै जिसके लिए खड़ा है।

दूसरी ओर, जब आप reinterpret_castसीपीयू को कॉल करते हैं तो कोई गणना नहीं करता है। यह सिर्फ मेमोरी में बिट्स के एक सेट को मानता है जैसे कि यह दूसरे प्रकार का था। इसलिए जब आप इस कीवर्ड के साथ परिवर्तित int*होते हैं float*, तो नए मान (पॉइंटर डेरेफेरिंग के बाद) का गणितीय अर्थ में पुराने मूल्य से कोई लेना-देना नहीं है।

उदाहरण: यह सच है किreinterpret_castएक कारण के कारण पोर्टेबल नहीं है - बाइट ऑर्डर (एंडियननेस)। लेकिन यह अक्सर आश्चर्यजनक रूप से इसका उपयोग करने का सबसे अच्छा कारण है। आइए उदाहरण की कल्पना करें: आपको फ़ाइल से बाइनरी 32 बिट नंबर पढ़ना है, और आप जानते हैं कि यह बड़ा एंडियन है। आपका कोड सामान्य होना चाहिए और बड़े एंडियन (जैसे कुछ एआरएम) और छोटे एंडियन (जैसे x86) सिस्टम पर ठीक से काम करता है। तो आपको बाइट ऑर्डर को जांचना होगा। यह संकलन समय पर अच्छी तरह से जाना जाता है ताकि आप constexprफ़ंक्शन लिख सकें : आप इसे प्राप्त करने के लिए एक फ़ंक्शन लिख सकते हैं:

/*constexpr*/ bool is_little_endian() {
  std::uint16_t x=0x0001;
  auto p = reinterpret_cast<std::uint8_t*>(&x);
  return *p != 0;
}

स्पष्टीकरण:x मेमोरी मेंबाइनरी प्रतिनिधित्व0000'0000'0000'0001(बड़ा) या0000'0001'0000'0000(थोड़ा एंडियन) हो सकता है। पुनरावर्तक-कास्टिंग के बादpसूचक केतहत बाइटक्रमशः0000'0000याहो सकता है0000'0001। यदि आप स्थैतिक-कास्टिंग का उपयोग करते हैं, तो यह हमेशा रहेगा0000'0001, कोई फर्क नहीं पड़ता कि एंडियनस का उपयोग किया जा रहा है।

संपादित करें:

पहले संस्करण में मैंने is_little_endianहोने के लिए उदाहरण कार्य किया constexpr। यह नवीनतम gcc (8.3.0) पर ठीक संकलन करता है, लेकिन मानक कहता है कि यह अवैध है। क्लैंग कंपाइलर इसे संकलित करने से इनकार करता है (जो सही है)।


1
अच्छा उदाहरण! मैं uint16_t के लिए शॉर्ट को बदलूंगा और uint8_t के लिए अहस्ताक्षरित चार को मानव के लिए कम अस्पष्ट बनाऊंगा।
जन तुरो '

@ जनतुरो सच है, हम यह नहीं मान सकते कि shortस्मृति में 16 बिट्स लगते हैं। सही किया।
जस्कमार

1
उदाहरण गलत है। reinterpret_cast को कॉन्स्ट्रेक्स फ़ंक्शंस में अनुमति नहीं है
माइकल वीक्स्लर

1
सबसे पहले, यह कोड नवीनतम क्लैंग (7.0.0) और जीसीसी (8.2.0) दोनों द्वारा खारिज कर दिया गया है। दुर्भाग्य से मुझे औपचारिक भाषा में सीमा नहीं मिली। सभी मुझे मिल सकता था social.msdn.microsoft.com/Forums/vstudio/en-US/…
माइकल वीक्सलर

2
अधिक विशेष रूप से, en.cppreference.com/w/cpp/language/constant_expression (आइटम 16) स्पष्ट रूप से बताता है कि पुनर्व्याख्या_कास्ट का उपयोग निरंतर अभिव्यक्ति में नहीं किया जा सकता है। इसके अलावा github.com/cplusplus/draft/blob/master/papers/N3797.pdf (5.19 स्थिर भाव) पृष्ठ 125-126 पर देखें जो स्पष्ट रूप से रीइंटरप्रिट_कास्ट को नियमबद्ध करता है। फिर 7.1.5 कॉन्स्ट्रेक्स स्पेसियर आइटम 5 (पेज 146) * एक गैर-टेम्पलेट के लिए, नॉन-डिफॉल्ट कॉन्स्टेक्सप्र फंक्शन ... यदि कोई तर्क मान मौजूद नहीं है ... तो मूल स्थिर अभिव्यक्ति (5.19) का मूल्यांकन किया हुआ सबप्रेशन हो सकता है ), कार्यक्रम बीमार है *
माइकल वीक्स्लर

20

का अर्थ reinterpret_castC ++ मानक द्वारा परिभाषित नहीं है। इसलिए, सिद्धांत रूप में reinterpret_castआपके प्रोग्राम को क्रैश कर सकता है। अभ्यास में संकलक वह करने की कोशिश करते हैं जो आप अपेक्षा करते हैं, जो कि आप जो कुछ कर रहे हैं उसकी बिट्स की व्याख्या करना है जैसे कि वे जिस प्रकार से आप के लिए कास्टिंग कर रहे थे। यदि आप जानते हैं कि आप जो कंपाइलर उपयोग करने जा रहे हैं तो reinterpret_cast आप उसका उपयोग कर सकते हैं, लेकिन यह कहना कि यह पोर्टेबल है, झूठ बोल रहा होगा।

आपके द्वारा वर्णित मामले के लिए, और बहुत अधिक किसी भी मामले में जहां आप विचार reinterpret_castकर सकते हैं, आप static_castइसके बजाय किसी अन्य विकल्प का उपयोग कर सकते हैं । अन्य बातों के साथ मानक के पास यह कहना है कि आप क्या उम्मीद कर सकते हैं static_cast(.95.2.9):

"पॉवर्ड टू सीवी शून्य" प्रकार के एक संकेत को स्पष्ट रूप से ऑब्जेक्ट प्रकार के लिए एक पॉइंटर में परिवर्तित किया जा सकता है। ऑब्जेक्ट के प्रकार पॉइंटर को "पॉइंटर टू सीवी शून्य" में परिवर्तित करने के लिए ऑब्जेक्ट और मूल पॉइंटर प्रकार पर वापस मूल मान होगा।

तो आपके उपयोग के मामले में, यह स्पष्ट रूप से स्पष्ट है कि मानकीकरण समिति आपके उपयोग के लिए अभिप्रेत है static_cast


5
अपने प्रोग्राम को बिल्कुल क्रैश न करें। मानक reinterpret_cast के बारे में कुछ गारंटी प्रदान करता है। सिर्फ उतना नहीं जितना लोग अक्सर उम्मीद करते हैं।
jalf

1
यदि आप इसका सही उपयोग नहीं करते हैं। यही है, A से B तक का reinterpret_cast पूरी तरह से सुरक्षित और अच्छी तरह से परिभाषित है। लेकिन बी का मूल्य अनिर्दिष्ट है, और हां, अगर आप उस पर भरोसा करते हैं, तो बुरी चीजें हो सकती हैं। लेकिन कास्ट अपने आप में काफी सुरक्षित है, जब तक कि आप इसे केवल मानक तरीके से उपयोग करते हैं। ;)
जल्पफ

55
योग्य, मुझे संदेह है कि reinterpret_crash वास्तव में आपके प्रोग्राम को क्रैश कर सकता है। लेकिन reinterpret_cast नहीं होगा। ;)
जालफ

5
<विडंबना> मैंने इसे अपने संकलक पर आज़माया, और किसी तरह, इसे संकलित करने से इनकार कर दिया reinterpret_crash। किसी भी तरह से एक कंपाइलर बग मुझे मेरे पुनर्व्याख्या कार्यक्रम को क्रैश करने से नहीं रोकेगा। मैं एक बग ASAP! </
Irony

18
@paercebaltemplate<class T, U> T reinterpret_crash(U a) { return *(T*)nullptr; }

12

Reinterpret_cast का एक उपयोग यह है कि यदि आप (IEEE 754) फ़्लोट में बिटवाइज़ ऑपरेशंस लागू करना चाहते हैं। इसका एक उदाहरण फास्ट इनवर्स स्क्वायर-रूट ट्रिक था:

https://en.wikipedia.org/wiki/Fast_inverse_square_root#Overview_of_the_code

यह फ्लोट के द्विआधारी प्रतिनिधित्व को पूर्णांक के रूप में मानता है, इसे दाईं ओर शिफ्ट करता है और इसे स्थिर से घटाता है, जिससे प्रतिपादक को रोकना और नकारना पड़ता है। एक फ्लोट में वापस बदलने के बाद, यह न्यूटन-राफसन पुनरावृत्ति के अधीन है, इस अनुमान को और अधिक सटीक बनाने के लिए:

float Q_rsqrt( float number )
{
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;                       // evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );               // what the deuce? 
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

    return y;
}

यह मूल रूप से C में लिखा गया था, इसलिए C कास्ट का उपयोग करता है, लेकिन अनुरूप C ++ का कास्ट रीइंटरप्रिट_कास्ट है।


1
error: invalid cast of an rvalue expression of type 'int64_t {aka long long int}' to type 'double&' reinterpret_cast<double&>((reinterpret_cast<int64_t&>(d) >> 1) + (1L << 61))- ideone.com/6S4ijc
Orwellophile

1
मानक का कहना है कि यह अपरिभाषित व्यवहार है: en.cppreference.com/w/cpp/language/reinterpret_cast ("टाइप अलियासिंग" के तहत)
Cris Luengo

@ क्रिसलूंगो यदि मैं सभी के reinterpret_castसाथ स्थानापन्न करता हूं memcpy, तो क्या यह अभी भी यूबी है?
सैंडथॉर्न

@ सैंडथॉर्न: यह मानक के अनुसार यूबी है, लेकिन अगर यह आपकी वास्तुकला के लिए काम करता है, तो इसके बारे में चिंता न करें। यह चाल ठीक है, मुझे लगता है, इंटेल आर्किटेक्चर के लिए किसी भी कंपाइलर के लिए। यह अन्य आर्किटेक्चर पर इरादा (या यहां तक ​​कि दुर्घटना) के रूप में काम नहीं कर सका - उदाहरण के लिए यह संभव हो सकता है कि फ़्लोट्स और लॉन्ग्स को अलग-अलग मेमोरी डिब्बों में संग्रहीत किया जाता है (यह नहीं कि मुझे ऐसी किसी भी वास्तुकला का पता है, यह सिर्फ एक तर्क है ...) । memcpyनिश्चित रूप से इसे कानूनी बना देगा।
संकट लुगानो


2
template <class outType, class inType>
outType safe_cast(inType pointer)
{
    void* temp = static_cast<void*>(pointer);
    return static_cast<outType>(temp);
}

मैंने निष्कर्ष निकालने की कोशिश की और टेम्प्लेट का उपयोग करके एक सरल सुरक्षित कास्ट लिखा। ध्यान दें कि यह समाधान किसी फ़ंक्शन पर संकेत देने की गारंटी नहीं देता है।


1
क्या? क्यों परेशान? यह reinterpret_castइस स्थिति में पहले से ही ठीक है: "एक ऑब्जेक्ट पॉइंटर को स्पष्ट रूप से एक अलग प्रकार के ऑब्जेक्ट पॉइंटर में परिवर्तित किया जा सकता है। [72] जब ऑब्जेक्ट पॉइंटर प्रकार का एक प्रिव्यू v ऑब्जेक्ट पॉइंटर प्रकार में बदल जाता है" पॉइंटर टू सीवी T , परिणाम है static_cast<cv T*>(static_cast<cv void*>(v))। " - N3797
अंडरस्कोर_ड

c++2003मानक के रूप में मुझे पता नहीं है कि reinterpret_castकरता हैstatic_cast<cv T*>(static_cast<cv void*>(v))
साशा ज़ेज़ुलिंस्की

1
ठीक है, सच है, लेकिन मैं 13 साल पहले के संस्करण के बारे में परवाह नहीं करता हूं, और न ही अधिकांश कोडर चाहिए यदि (जैसा कि संभावना है) वे इससे बच सकते हैं। उत्तर और टिप्पणियाँ वास्तव में नवीनतम उपलब्ध मानक को प्रतिबिंबित करना चाहिए जब तक कि अन्यथा निर्दिष्ट न हो ... IMHO। वैसे भी, मुझे लगता है कि समिति ने 2003 के बाद इसे स्पष्ट रूप से जोड़ने की आवश्यकता महसूस की। (क्योंकि IIRC, यह C ++ 11 में भी ऐसा ही था)
अंडरस्कोर_ड

पहले C++03यह था C++98। पोर्टेबल सी के बजाय पुराने सी ++ का उपयोग करने वाले प्रोजेक्ट्स के टन कभी-कभी आपको पोर्टेबिलिटी के बारे में ध्यान रखना पड़ता है। उदाहरण के लिए आपको Solaris, AIX, HPUX, Windows पर समान कोड का समर्थन करना होगा। जहां यह संकलक निर्भरता और पोर्टेबिलिटी की बात आती है, यह मुश्किल है। तो पोर्टेबिलिटी नरक शुरू करने का एक अच्छा उदाहरण reinterpret_castआपके कोड में एक का उपयोग करना है
साशा ज़ेज़ुलिंस्की

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

1

पहले आपके पास एक विशिष्ट प्रकार में कुछ डेटा हैं जैसे यहाँ int:

int x = 0x7fffffff://==nan in binary representation

फिर आप एक ही चर को दूसरे प्रकार जैसे फ्लोट के रूप में एक्सेस करना चाहते हैं: आप इसके बीच निर्णय ले सकते हैं

float y = reinterpret_cast<float&>(x);

//this could only be used in cpp, looks like a function with template-parameters

या

float y = *(float*)&(x);

//this could be used in c and cpp

BRIEF: इसका मतलब है कि एक ही मेमोरी को एक अलग प्रकार के रूप में उपयोग किया जाता है। तो आप फ्लोट्स के बाइनरी अभ्यावेदन को अंतर के रूप में बदल सकते हैं जैसे कि ऊपर तैरने के लिए। उदाहरण के लिए 0x80000000 -0 है (मंटिसा और प्रतिपादक शून्य हैं, लेकिन संकेत, एमएसबी, एक है। यह भी डबल्स और लंबे डबल्स के लिए काम करता है।

ऑप्टिमाइज़: मुझे लगता है कि रीइंटरप्रिटेट_कास्ट को कई कंपाइलरों में ऑप्टिमाइज़ किया जाएगा, जबकि सी-कास्टिंग पॉइंटरारिथेमैटिक (मूल्य को मेमोरी में कॉपी किया जाना चाहिए, क्योंकि पॉइंटर्स सीपीयू-रजिस्टरों को इंगित नहीं कर सकते हैं)।

नोट: दोनों ही मामलों में आपको कास्ट से पहले एक वैरिएबल में कास्ट वैल्यू बचानी चाहिए! यह मैक्रो मदद कर सकता है:

#define asvar(x) ({decltype(x) __tmp__ = (x); __tmp__; })

यह सच है कि "इसका मतलब है कि एक ही मेमोरी का उपयोग एक अलग प्रकार के रूप में किया जाता है" लेकिन यह विशिष्ट प्रकार के जोड़े तक ही सीमित है। अपने उदाहरण में reinterpret_castप्रपत्र intको float&अपरिभाषित व्यवहार है।
jaskmar

1

उपयोग करने का एक कारण यह है reinterpret_castकि जब एक आधार वर्ग के पास एक व्यवहार्य नहीं है, लेकिन एक व्युत्पन्न वर्ग करता है। उस मामले में, static_castऔर reinterpret_castअलग-अलग सूचक मानों में परिणाम होगा (यह ऊपर दिए गए जल्फ द्वारा उल्लिखित एटिपिकल केस होगा )। एक अस्वीकरण के रूप में, मैं यह नहीं कह रहा हूं कि यह मानक का हिस्सा है, लेकिन कई व्यापक संकलक का कार्यान्वयन है।

एक उदाहरण के रूप में, नीचे दिया गया कोड लें:

#include <cstdio>

class A {
public:
    int i;
};

class B : public A {
public:
    virtual void func() {  }
};

int main()
{
    B b;
    const A* a = static_cast<A*>(&b);
    const A* ar = reinterpret_cast<A*>(&b);

    printf("&b = %p\n", &b);
    printf(" a = %p\n", a);
    printf("ar = %p\n", ar);
    printf("difference = %ld\n", (long int)(a - ar));

    return 0;
}

जो कुछ इस तरह से आउटपुट करता है:

& b = 0x7ffe10e68b38
a = 0x7ffe10e68b40
ar = 0x7ffe10e68b38
अंतर = 2

सभी कंपाइलरों में मैंने कोशिश की (MSVC 2015 और 2017, clang 8.0.0, gcc 9.2, icc 19.0.1 - अंतिम 3 के लिए गॉडबॉल्ट देखें ) 2 (MSVC के लिए 4) static_castसे भिन्न के परिणाम reinterpret_cast। अंतर के बारे में चेतावनी देने वाला एकमात्र संकलक था:

17:16: चेतावनी: वर्ग 'बी *' से 'रीइंटरप्रिटेट_कास्ट' 'नॉन-ज़ीरो ऑफ़सेट्स' ए * के आधार पर इसके 'स्थैतिक_कास्ट' [भिन्न-आधार-वर्ग] कॉन्स्टेंस
ए * आर.इंटरटेन्प्रेज़_कास्ट (& b) से भिन्न व्यवहार करता है। ;
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~
17:16: ध्यान दें: '
ए' ar = reinterpret_cast (& b) कास्ट करते समय पॉइंटर को सही ढंग से समायोजित करने के लिए 'static_cast' का उपयोग करें। ;
^ ~~~~~~~~~~~~~~~~
static_cast

एक आखिरी चेतावनी है कि अगर आधार वर्ग कोई डेटा सदस्य हैं (उदाहरण के लिए है int i;) तो बजना, जीसीसी, और आईसीसी एक ही पते के लिए वापस जाने के reinterpret_castलिए के रूप में static_castहै, जबकि अभी भी MSVC नहीं करता है।


1

यहाँ reinterpret_castअवी जिन्सबर्ग के कार्यक्रम का एक संस्करण है जो स्पष्ट रूप से क्रिस लुएंगो, फ्लोडिन, और सीएमडीएलपी द्वारा उल्लिखित की गई संपत्ति का चित्रण करता है : संकलक इंगित-स्मृति स्थान को मानता है जैसे कि यह नए प्रकार की वस्तु थी:

#include <iostream>
#include <string>
#include <iomanip>
using namespace std;

class A
{
public:
    int i;
};

class B : public A
{
public:
    virtual void f() {}
};

int main()
{
    string s;
    B b;
    b.i = 0;
    A* as = static_cast<A*>(&b);
    A* ar = reinterpret_cast<A*>(&b);
    B* c = reinterpret_cast<B*>(ar);

    cout << "as->i = " << hex << setfill('0')  << as->i << "\n";
    cout << "ar->i = " << ar->i << "\n";
    cout << "b.i   = " << b.i << "\n";
    cout << "c->i  = " << c->i << "\n";
    cout << "\n";
    cout << "&(as->i) = " << &(as->i) << "\n";
    cout << "&(ar->i) = " << &(ar->i) << "\n";
    cout << "&(b.i) = " << &(b.i) << "\n";
    cout << "&(c->i) = " << &(c->i) << "\n";
    cout << "\n";
    cout << "&b = " << &b << "\n";
    cout << "as = " << as << "\n";
    cout << "ar = " << ar << "\n";
    cout << "c  = " << c  << "\n";

    cout << "Press ENTER to exit.\n";
    getline(cin,s);
}

जो इस तरह से उत्पादन में परिणाम:

as->i = 0
ar->i = 50ee64
b.i   = 0
c->i  = 0

&(as->i) = 00EFF978
&(ar->i) = 00EFF974
&(b.i) = 00EFF978
&(c->i) = 00EFF978

&b = 00EFF974
as = 00EFF978
ar = 00EFF974
c  = 00EFF974
Press ENTER to exit.

यह देखा जा सकता है कि B ऑब्जेक्ट को पहले B-विशिष्ट डेटा के रूप में मेमोरी में बनाया गया है, उसके बाद एम्बेडेड ए ऑब्जेक्ट। static_castसही ढंग से एम्बेडेड एक वस्तु का पता देता है, और सूचक द्वारा बनाई static_castसही ढंग से डेटा फ़ील्ड का मान देता है। सूचक द्वारा उत्पन्न reinterpret_castव्यवहार करता है bकी स्मृति स्थान के रूप में अगर यह एक सादे एक वस्तु थे, और इसलिए इसे कुछ बी-विशिष्ट डेटा लौटाता है जब सूचक की कोशिश करता डेटा फ़ील्ड प्राप्त करने के लिए, जैसे कि वह इस क्षेत्र की सामग्री को थे।

एक का उपयोग reinterpret_castएक सूचक को अहस्ताक्षरित पूर्णांक में बदलने के लिए होता है (जब संकेत और अहस्ताक्षरित पूर्णांक समान आकार होते हैं):

int i; unsigned int u = reinterpret_cast<unsigned int>(&i);


-6

त्वरित उत्तर: static_castयदि यह संकलित करता है तो उपयोग करें , अन्यथा सहारा लें reinterpret_cast


-16

एफएक्यू पढ़ें ! C में C ++ डेटा को रखना जोखिम भरा हो सकता है।

C ++ में, किसी ऑब्जेक्ट के लिए एक पॉइंटर को void *बिना किसी जाति में परिवर्तित किया जा सकता है । लेकिन यह दूसरे तरीके से सच नहीं है। आपको static_castमूल सूचक को वापस लाने के लिए एक की आवश्यकता होगी ।

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