2012-12-24 12 views
5

फ्लोट से बाइट सरणी लंबाई 4 (char * की सरणी) को कैसे परिवर्तित करें? मुझे नेटवर्क पर कुछ डेटा भेजने की जरूरत है, टीसीपी, और एक बाइट सरणी के रूप में फ्लोट भेजने की जरूरत है। (मुझे दो दशमलव अंकों की सटीकता पता है, इसलिए फिलहाल मैं क्लाइंट साइड 100 से गुणा करता हूं और 100 से सर्वर पर विभाजित होता है - मूल रूप से पूर्णांक में परिवर्तित होता है और फिर & 0xff < < संचालन के साथ बाइट्स ढूंढें)। लेकिन यह बदसूरत है और समय के दौरान परिशुद्धता खो सकता है।फ्लोट से बाइट सरणी लंबाई 4 (char * की सरणी) को कैसे परिवर्तित करें?

+0

मुझे लगता है कि आपको सटीकता रखने के लिए 8 बाइट की आवश्यकता है। –

+0

@ हेनो ब्रांड्समा सामान्य रूप से यह 'डबल' है। अधिकांश आधुनिक प्रणालियों पर, 'फ्लोट' 4-बाइट आईईईई -754 प्रारूप है। –

+0

अपने अंतिम समाधान में एंडियन एकाउंटिंग को छूट न दें जबतक कि आप अपने क्लाइंट/सर्वर को एक प्रारूप (बड़े या छोटे) पर सीमित नहीं कर रहे हैं। – WhozCraig

उत्तर

9

बाइट्स की एक दृश्य के रूप में किसी भी प्रकार पढ़ना काफी सरल है:

float f = 0.5f; 

unsigned char const * p = reinterpret_cast<unsigned char const *>(&f); 

for (std::size_t i = 0; i != sizeof(float); ++i) 
{ 
    std::printf("The byte #%zu is 0x%02X\n", i, p[i]); 
} 

एक नेटवर्क धारा से एक नाव के लिए लेखन इसी तरह काम करता है, केवल आप const बाहर छोड़ चाहते हैं।

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

+0

लेकिन, ज़ाहिर है, अगर वह नेटवर्क पर बाइट लिखना है तो यह वास्तव में उसकी मदद नहीं करता है। –

+0

@JamesKanze: 'लिखने (FD, पी, sizeof (नाव))' ... बेशक, आप उपयोग कर सकते हैं सवाल जो कर सकते हैं * पढ़ा * कि :-) –

+0

वहाँ व्यावहारिक रूप से किसी भी हालत जहां 'write' सही होगा है। लेकिन सवाल नेटवर्क पर उत्पादन करना था। तो वह जो लिखता है वह प्रारूप के अनुरूप होना चाहिए जो प्रोटोकॉल का उपयोग कर रहा है। –

5

नेटवर्क प्रोटोकॉल में फ्लोट के प्रारूप को निर्धारित करने के लिए आपको सबसे पहले करना है। सिर्फ यह जानकर कि यह 4 बाइट्स आपको बहुत कुछ नहीं बताता है: आईबीएम मेनफ्रेम, ओरेकल स्पार्क और सामान्य पीसी में चार बाइट फ्लोट हैं, लेकिन उनके पास तीन अलग प्रारूप हैं। एक बार जब आप प्रारूप पता है, यह और अपने पोर्टेबिलिटी आवश्यकताओं के आधार पर, दो अलग अलग रणनीतियों इस्तेमाल किया जा सकता:

तो प्रोटोकॉल में प्रारूप आईईईई (सबसे अक्सर मामले), है और आप हो की जरूरत नहीं है मशीनों के लिए पोर्टेबल जो आईईईई नहीं कर रहे हैं (Windows और अधिकांश यूनिक्स आईईईई रहे हैं — सबसे mainframes नहीं), तो आप प्रकार punning उपयोग कर सकते हैं कि, का उपयोग कर एक uint32_t को नाव, और उत्पादन कन्वर्ट करने के लिए या तो:

std::ostream& 
output32BitUInt(std::ostream& dest, uint32_t value) 
{ 
    dest.put((value >> 24) & 0xFF); 
    dest.put((value >> 16) & 0xFF); 
    dest.put((value >> 8) & 0xFF); 
    dest.put((value  ) & 0xFF); 
} 

बड़े-एंडियन (सामान्य नेटवर्क ऑर्डर) के लिए, या:

std::ostream& 
output32BitUInt(std::ostream& dest, uint32_t value) 
{ 
    dest.put((value  ) & 0xFF); 
    dest.put((value >> 8) & 0xFF); 
    dest.put((value >> 16) & 0xFF); 
    dest.put((value >> 24) & 0xFF); 
} 

छोटे-अंत (कुछ प्रोटोकॉल द्वारा उपयोग किया जाता है) के लिए। आप का उपयोग करने वाले प्रोटोकॉल के लिए परिभाषित प्रारूप पर निर्भर करेंगे।

float से uint32_t में कनवर्ट करने के लिए, आपको अपना कंपाइलर देखना होगा। memcpy का उपयोग करने का एकमात्र तरीका मानक द्वारा पूरी तरह से गारंटीकृत है; इरादा यह है कि फ्लोट काम पर reinterpret_cast<uint32_t&> का उपयोग करके, और अधिकांश (सभी?) कंपाइलर union का उपयोग करके भी समर्थन करते हैं।

आप के रूप में अच्छी mainframes करने के लिए पोर्टेबल होने की जरूरत है, या प्रारूप आईईईई के अलावा कुछ है, तो आप लक्ष्य प्रारूप में, प्रतिपादक निकालने नाव से साइन इन करें और अपूर्णांश, और उत्पादन प्रत्येक की आवश्यकता होगी ।निम्नलिखित की तरह कुछ पर उत्पादन आईईईई बड़े endian करने के लिए काम करना चाहिए (mainframes जो आईईईई का उपयोग नहीं करते सहित) किसी भी मशीन, और आप कुछ पता चलना चाहिए:

oxdrstream& 
oxdrstream::operator<<(
    float    source) 
{ 
    BytePutter   dest(*this) ; 
    bool    isNeg = source < 0 ; 
    if (isNeg) { 
     source = - source ; 
    } 
    int     exp ; 
    if (source == 0.0) { 
     exp = 0 ; 
    } else { 
     source = ldexp(frexp(source, &exp), 24) ; 
     exp += 126 ; 
    } 
    uint32_t    mant = source ; 
    dest.put((isNeg ? 0x80 : 0x00) | exp >> 1) ; 
    dest.put(((exp << 7) & 0x80) | ((mant >> 16) & 0x7F)) ; 
    dest.put(mant >> 8) ; 
    dest.put(mant  ) ; 
    return *this ; 
} 

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

2

बस एक में डेटा ओवरले क्षेत्र, सी

union dataUnion { 
    float f; 
    char fBuff[sizeof(float)]; 
} 
// to use: 
dataUnion myUnion; 
// 
myUnion.f = 3.24; 
for(int i=0;i<sizeof(float);i++) 
    fputc(myUnion.fbuff[i],fp); // or what ever stream output.... 
संबंधित मुद्दे