ओपन सोर्स program I wrote में दो बार सुरक्षित रूप से दंडित करने के लिए, मैं फ़ाइल से बाइनरी डेटा (किसी अन्य प्रोग्राम द्वारा लिखित) पढ़ रहा हूं और इनट्स, युगल, और अन्य मिश्रित डेटा प्रकारों को आउटपुट कर रहा हूं। चुनौतियों में से एक यह है कि इसे दोनों एंडियननेस की 32-बिट और 64-बिट मशीनों पर चलने की आवश्यकता है, जिसका अर्थ है कि मैं बहुत कम स्तर के बिट-ट्विडलिंग करने के लिए समाप्त होता हूं। मुझे एक (बहुत) टाइपिंग और सख्त एलियासिंग टाइप करने के बारे में कुछ पता है और यह सुनिश्चित करना चाहता हूं कि मैं सही तरीके से काम कर रहा हूं।सी
असल में, यह एक चार * से विभिन्न आकार के एक पूर्णांक कन्वर्ट करने के लिए आसान है:
int64_t snativeint64_t(const char *buf)
{
/* Interpret the first 8 bytes of buf as a 64-bit int */
return *(int64_t *) buf;
}
और मैं सहायता कार्यों की एक डाली बाइट आदेश स्वैप करने के लिए आवश्यकतानुसार ऐसे के रूप में है,:
int64_t swappedint64_t(const int64_t wrongend)
{
/* Change the endianness of a 64-bit integer */
return (((wrongend & 0xff00000000000000LL) >> 56) |
((wrongend & 0x00ff000000000000LL) >> 40) |
((wrongend & 0x0000ff0000000000LL) >> 24) |
((wrongend & 0x000000ff00000000LL) >> 8) |
((wrongend & 0x00000000ff000000LL) << 8) |
((wrongend & 0x0000000000ff0000LL) << 24) |
((wrongend & 0x000000000000ff00LL) << 40) |
((wrongend & 0x00000000000000ffLL) << 56));
}
रनटाइम पर, कार्यक्रम मशीन के endianness पता लगाता है और एक समारोह सूचक को ऊपर की एक प्रदान करती है:
int64_t (*slittleint64_t)(const char *);
if(littleendian) {
slittleint64_t = snativeint64_t;
} else {
slittleint64_t = sswappedint64_t;
}
अब, मुश्किल हिस्सा तब आता है जब मैं एक char * को दो बार डालने की कोशिश कर रहा हूं।
union
{
double d;
int64_t i;
} int64todouble;
int64todouble.i = slittleint64_t(bufoffset);
printf("%lf", int64todouble.d);
हालांकि, कुछ compilers "int64todouble.i" काम दूर अनुकूलन और कार्यक्रम को तोड़ सकते थे: मैं तो जैसे endian-गमागमन कोड का फिर से उपयोग करना चाहते हैं। पर विचार करते समय ऐसा करने का एक सुरक्षित तरीका है कि इस कार्यक्रम को प्रदर्शन के लिए अनुकूलित किया जाना चाहिए, और यह भी कि मैं बदल सकता हूं कि परिवर्तनों के समांतर सेट को चार * से को सीधे डालने के लिए नहीं लिखना चाहिए? यदि दंड की यूनियन विधि सुरक्षित है, तो क्या मुझे का उपयोग करने के लिए snativeint64_t जैसे कार्यों को दोबारा लिखना चाहिए?
snativeint64_t:
movq (%rdi), %rax
ret
:
int64_t snativeint64_t(const char *buf)
{
/* Interpret the first 8 bytes of buf as a 64-bit int */
int64_t output;
memcpy(&output, buf, 8);
return output;
}
अपने मूल कोड के रूप में ठीक उसी कोडांतरक में संकलित किया:
मैं क्योंकि रूपांतरण कार्यों को फिर से लिखा Steve Jessop's जवाब का उपयोग कर तो की तरह, memcpy उपयोग करने के लिए समाप्त हो गया
दो में से, memcpy संस्करण स्पष्ट रूप से व्यक्त करता है कि मैं क्या करने की कोशिश कर रहा हूं और यहां तक कि सबसे बेवकूफ कंपाइलरों पर भी काम करना चाहिए।
एडम, आपका उत्तर भी अद्भुत था और मैंने इससे बहुत कुछ सीखा। पोस्ट करने का शुक्रिया!
पूर्णांक रूपांतरण केवल तभी सुरक्षित है जब चार सूचक पर्याप्त रूप से गठबंधन हो। –
इस कार्यक्रम में, यह हमेशा होगा। –
रनटाइम पर एंडियन-नेस का पता क्यों लगा? मैं कल्पना करता हूं कि कार्यक्रम केवल उस आर्क पर काम कर सकता है जिसे संकलित किया गया था जिसके लिए एक विशिष्ट एंडियन-नेस होगा (मुझे पता है कि कुछ आपको चुनने देते हैं), तो क्यों नॉटल और पसंद की तरह नहीं करते हैं और इसे संकलित समय निर्णय लेते हैं? –