2012-12-20 96 views
13

नोट: मैंने गलती से static_cast मूल रूप से पूछा; यही कारण है कि शीर्ष जवाब पहले static_cast का उल्लेख करता है।क्या यह फ़्लोट करने के लिए एक पूर्णांक reinterpret_cast सुरक्षित है?

मेरे पास कुछ एंडिनल फ्लोट मानों वाली कुछ बाइनरी फ़ाइलें हैं। मैं उन्हें मशीन-स्वतंत्र तरीके से पढ़ना चाहता हूं। मेरी बाइट-स्वैपिंग दिनचर्या (एसडीएल से) हस्ताक्षरित पूर्णांक प्रकारों पर काम करती है।

क्या यह स्याही और फ्लोट्स के बीच बस डालना सुरक्षित है?

float read_float() { 
    // Read in 4 bytes. 
    Uint32 val; 
    fread(&val, 4, 1, fp); 
    // Swap the bytes to little-endian if necessary. 
    val = SDL_SwapLE32(val); 
    // Return as a float 
    return reinterpret_cast<float &>(val); //XXX Is this safe? 
} 

मैं चाहता हूं कि यह सॉफ्टवेयर यथासंभव पोर्टेबल हो।

+2

आप पॉइंटर या संदर्भ प्रकारों में केवल 'reinterpret_cast' कर सकते हैं; आपके द्वारा पोस्ट किया गया कोड संकलित नहीं होगा। – Praetorian

+1

आप शायद फ्लोट परिणाम = reintrepret_cast (वैल) जैसे कुछ मतलब; –

+0

ओह। मुझे वास्तव में पहले संकलित करने की कोशिश करनी चाहिए:/ – QuasarDonkey

उत्तर

24

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

आप जो करना चाहते हैं वह float मान का ऑब्जेक्ट प्रस्तुति Uint32 चर के रूप में घोषित स्मृति के एक टुकड़े में बना रहा है। परिणामी float मान का उत्पादन करने के लिए आपको उस स्मृति को दोबारा परिभाषित करने की आवश्यकता है। यह, reinterpret_cast

assert(sizeof(float) == sizeof val); 
return reinterpret_cast<float &>(val); 

द्वारा प्राप्त किया जाएगा या, अगर आप चाहें एक ही बात

assert(sizeof(float) == sizeof val); 
return *reinterpret_cast<float *>(&val); 

का एक सूचक संस्करण हालांकि के प्रकार-punning इस तरह एक संकलक कि इस प्रकार में काम करने की गारंटी नहीं है सख्त एलियासिंग semantics। एक और तरीका यह होगा कि

float f; 

assert(sizeof f == sizeof val); 
memcpy(&f, &val, sizeof f); 

return f; 

या आप स्मृति पुनरावृत्ति को लागू करने के लिए प्रसिद्ध यूनियन हैक का उपयोग कर सकते हैं। सख्त अलियासिंग अर्थ विज्ञान के साथ कुछ compilers प्रकार punning

assert(sizeof(float) == sizeof(Uint32)); 

union { 
    Uint32 val; 
    float f; 
} u = { val }; 

return u.f; 
+0

क्षमाप्रार्थी, आप सही हैं (मेरा मतलब है reinterpret_cast, static_cast नहीं)। मैंने इसे प्रतिबिंबित करने के लिए प्रश्न अपडेट किया है। – QuasarDonkey

+0

धन्यवाद। मुझे "टाइप-पनिंग" शब्द से अवगत नहीं था। यह कुछ उपयोगी जानकारी बदल गया है। मैंने जो पढ़ा है उसके आधार पर, मुझे लगता है कि मैं * यूनियन * चाल के साथ जाऊंगा, ऐसा लगता है कि यह अच्छी तरह से समर्थित है। – QuasarDonkey

+0

क्या होगा यदि हम 4 के गुणा के पिछले प्राप्त करने के लिए पहले * शून्य और फिर फ्लोट * करने के लिए डाले? क्या ये सुरक्षित है? –

2

संक्षेप में की आधिकारिक तौर पर समर्थित विधि के रूप में संघ-आधारित दृष्टिकोण सुरक्षित रखते हैं, यह गलत है। आप एक फ्लोट के लिए एक पूर्णांक कास्टिंग कर रहे हैं, और उस समय संकलक द्वारा एक पूर्णांक के रूप में इसका अर्थ लिया जाएगा। उपरोक्त प्रस्तुत संघ समाधान।

संघ के रूप में बात की एक ही तरह करने के लिए एक और तरीका है इस का उपयोग किया जाएगा है:

return *reinterpret_cast<float*>(&val); 

यह भी उतना ही सुरक्षित/ऊपर संघ समाधान के रूप में असुरक्षित है, और मैं निश्चित रूप से एक ज़ोर करने की सिफारिश करेंगे सुनिश्चित करें कि फ्लोट int के समान आकार है।

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

+0

वैसे मैं अब टाइप-पनिंग पर विकी लेख पढ़ रहा हूं। यह कहता है: "कई सामान्य प्लेटफार्मों पर, पॉइंटर पनिंग के उपयोग से समस्याएं पैदा हो सकती हैं यदि अलग-अलग पॉइंटर्स मशीन-विशिष्ट तरीकों से गठबंधन होते हैं ... इस एलियासिंग समस्या को संघ के उपयोग से तय किया जा सकता है"। – QuasarDonkey

+0

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

+0

यह समझ में आता है, लेकिन मुझे लगता है कि मैं संघ के साथ रहूंगा क्योंकि यह बाइनरी के लिए सबसे अच्छा विकल्प प्रतीत होता है। दुर्भाग्य से, मैं पाठ का उपयोग नहीं कर सकता क्योंकि मैं विरासत प्रणाली से फ़ाइलों का समर्थन कर रहा हूं। – QuasarDonkey