इंटेल प्रोसेसर (और शायद कुछ अन्य) भंडारण के लिए छोटे एंडियन प्रारूप का उपयोग करते हैं।
मुझे हमेशा आश्चर्य होता है कि कोई क्यों बाइट्स को रिवर्स ऑर्डर में स्टोर करना चाहता है। क्या इस प्रारूप का बड़े एंडियन प्रारूप पर कोई लाभ है?
इंटेल प्रोसेसर (और शायद कुछ अन्य) भंडारण के लिए छोटे एंडियन प्रारूप का उपयोग करते हैं।
मुझे हमेशा आश्चर्य होता है कि कोई क्यों बाइट्स को रिवर्स ऑर्डर में स्टोर करना चाहता है। क्या इस प्रारूप का बड़े एंडियन प्रारूप पर कोई लाभ है?
जवाबों:
दोनों तरह से तर्क हैं, लेकिन एक बिंदु यह है कि थोड़ा-एंडियन सिस्टम में, स्मृति में दिए गए मान का पता, जिसे 32, 16 या 8 बिट चौड़ाई के रूप में लिया जाता है, एक ही है।
दूसरे शब्दों में, यदि आपके पास मेमोरी में दो बाइट का मूल्य है:
0x00f0 16
0x00f1 0
16-बिट मान के रूप में '16' (अधिकांश 32-बिट सिस्टम पर c) छोटा या 8-बिट मान के रूप में (आमतौर पर c 'char') केवल आपके द्वारा उपयोग किए जाने वाले भ्रूण के निर्देश में परिवर्तन करता है - आपके द्वारा प्राप्त किया गया पता नहीं से।
एक बड़े-एंडियन सिस्टम पर, जैसा कि ऊपर दिया गया है:
0x00f0 0
0x00f1 16
आपको पॉइंटर को बढ़ाना होगा और फिर नए मूल्य पर संकरा लाने के लिए ऑपरेशन करना होगा।
इसलिए, संक्षेप में, 'थोड़ा एंडियन सिस्टम पर, कास्ट एक नो-ऑप हैं।'
मुझे हमेशा आश्चर्य होता है कि कोई क्यों बाइट्स को रिवर्स ऑर्डर में स्टोर करना चाहता है।
बिग-एंडियन और लिटिल-एंडियन केवल "सामान्य आदेश" और "रिवर्स ऑर्डर" मानवीय दृष्टिकोण से हैं, और उसके बाद ही यदि ये सभी सत्य हैं ...
वे सभी मानव सम्मेलन हैं जो सीपीयू में बिल्कुल भी मायने नहीं रखते हैं। यदि आप # 1 और # 2, और फ्लिप # 3 को बनाए रखने के लिए थे, तो छोटे-एंडियन अरबी या हिब्रू पढ़ने वाले लोगों के लिए "पूरी तरह से प्राकृतिक" प्रतीत होंगे, जिन्हें राइट-टू-लेफ्ट लिखा जाता है।
और ऐसे अन्य मानव सम्मेलन हैं जो बड़े-बड़े हैं जो अप्राकृतिक लगते हैं, जैसे ...
जब मैं ज्यादातर 68K और PowerPC प्रोग्रामिंग कर रहा था, मैंने बड़े-एंडियन को "सही" और छोटे-एंडियन को "गलत" माना। लेकिन जब से मैं और अधिक एआरएम और इंटेल काम कर रहा हूँ, मैं छोटे एंडियन के लिए इस्तेमाल किया है। यह वास्तव में कोई फर्क नहीं पड़ता।
ठीक है, यहाँ कारण है जैसा कि मैंने इसे बताया है: मुझे जोड़ और घटाव
जब आप मल्टी-बाइट संख्या जोड़ते हैं या घटाते हैं, तो आपको कम से कम महत्वपूर्ण बाइट के साथ शुरू करना होगा। यदि आप उदाहरण के लिए दो 16-बिट संख्या जोड़ रहे हैं, तो कम से कम महत्वपूर्ण बाइट से लेकर सबसे महत्वपूर्ण बाइट तक एक कैरी हो सकती है, इसलिए आपको यह देखना होगा कि कैरी है या नहीं। यह वही कारण है कि आप लॉन्गहैंड जोड़ते समय सबसे सही अंक से शुरू करते हैं। आप बाईं ओर से शुरू नहीं कर सकते।
एक 8-बिट सिस्टम पर विचार करें जो मेमोरी से क्रमिक रूप से बाइट प्राप्त करता है। यदि यह पहले कम से कम महत्वपूर्ण बाइट प्राप्त करता है , तो यह अतिरिक्त करना शुरू कर सकता है जबकि सबसे महत्वपूर्ण बाइट को स्मृति से प्राप्त किया जा रहा है। यह समानता इसलिए है कि सिस्टम जैसे छोटे एंडियन में प्रदर्शन बेहतर है। यदि इसे तब तक इंतजार करना पड़ता है जब तक कि दोनों बाइट्स को स्मृति से नहीं लिया जाता है, या उन्हें उल्टे क्रम में लाया जाता है, तो अधिक समय लगेगा।
यह पुराने 8-बिट सिस्टम पर है। एक आधुनिक सीपीयू पर मुझे संदेह है कि बाइट ऑर्डर से कोई फर्क पड़ता है और हम केवल ऐतिहासिक कारणों के लिए थोड़ा एंडियन का उपयोग करते हैं।
8 बिट प्रोसेसर के साथ यह निश्चित रूप से अधिक प्रभावोत्पादक था, आप विभिन्न कोड की आवश्यकता के बिना और अतिरिक्त मानों को बफर करने की आवश्यकता के बिना एक 8 या 16 बिट ऑपरेशन कर सकते हैं।
यदि आप एक बार में एक बाइट का काम कर रहे हैं तो यह कुछ अतिरिक्त संचालन के लिए अभी भी बेहतर है।
लेकिन कोई कारण नहीं है कि बड़ा-एंडियन अधिक स्वाभाविक है - अंग्रेजी में आप तेरह (छोटे एंडियन) और तेईस (बड़ा एंडियन) का उपयोग करते हैं
0x12345678
स्टोर किया जाता है 78 56 34 12
जबकि एक बीई सिस्टम पर यह 12 34 56 78
(बाइट 0 बाईं तरफ है, बाइट 3 दाईं ओर है)। ध्यान दें कि संख्या कितनी बड़ी है (बिट्स के संदर्भ में), इसके लिए अधिक स्वैपिंग की आवश्यकता होती है; WORD को एक स्वैप की आवश्यकता होगी; एक DWORD, दो पास (तीन कुल स्वैप); एक QWORD तीन पास (7 कुल), और इसी तरह। यही है, (bits/8)-1
स्वैप। एक अन्य विकल्प उन दोनों को आगे और पीछे की तरफ पढ़ रहा है (प्रत्येक बाइट को आगे की तरफ पढ़ रहा है, लेकिन पूरे # पीछे की तरफ स्कैन करता है)।
जापानी तिथि सम्मेलन "बड़ा एंडियन" है - yyyy / mm / dd। यह एल्गोरिदम को छांटने के लिए आसान है, जो सामान्य प्रथम-चरित्र-सबसे-महत्वपूर्ण नियम के साथ एक साधारण स्ट्रिंग-तुलना का उपयोग कर सकता है।
सबसे महत्वपूर्ण-फ़ील्ड-प्रथम रिकॉर्ड में संग्रहीत बड़े-एंडियन संख्याओं के लिए कुछ समान लागू होता है। फ़ील्ड्स के भीतर बाइट्स का महत्व क्रम रिकॉर्ड के भीतर फ़ील्ड्स के महत्व से मेल खाता है, इसलिए आप memcmp
रिकॉर्ड्स की तुलना करने के लिए उपयोग कर सकते हैं , न कि आप दो लॉन्गवर्ड, चार शब्दों या आठ अलग-अलग बाइट्स की तुलना कर रहे हैं।
खेतों के महत्व के क्रम को पलटें और आपको उतना ही फायदा मिले, लेकिन बड़े-एंडियन की बजाय छोटे-छोटे संख्याओं के लिए।
इसका बहुत कम व्यावहारिक महत्व है। चाहे आपका प्लेटफ़ॉर्म बड़ा-एंडियन हो या छोटा-सा एंडियन, आप इस ट्रिक का फायदा उठाने के लिए रिकॉर्ड फ़ील्ड ऑर्डर कर सकते हैं यदि आपको वास्तव में ज़रूरत है। यह सिर्फ एक दर्द है अगर आपको पोर्टेबल कोड लिखने की आवश्यकता है ।
मैं भी क्लासिक अपील के लिए एक लिंक शामिल हो सकता है ...
http://tools.ietf.org/rfcmarkup?url=ftp://ftp.rfc-editor.org/in-notes/ien/ien137.txt
संपादित करें
एक अतिरिक्त विचार। मैंने एक बार एक बड़ा पूर्णांक पुस्तकालय (अगर मैं कर सकता था) देखने के लिए लिखा है, और उसके लिए, 32-बिट-वाइड विखंडू को छोटे-एंडियन क्रम में संग्रहीत किया जाता है, भले ही प्लेटफ़ॉर्म उन बिट्स में बिट्स कैसे ऑर्डर करता है। कारण थे ...
बहुत सारे एल्गोरिदम केवल स्वाभाविक रूप से कम से कम महत्वपूर्ण छोर पर काम करना शुरू करते हैं, और चाहते हैं कि उन छोरों का मिलान किया जाए। उदाहरण के लिए, कैर्री अधिक से अधिक महत्वपूर्ण अंकों को प्रचारित करता है, इसलिए यह कम से कम महत्वपूर्ण अंत शुरू करने के लिए समझ में आता है।
मूल्य बढ़ने या सिकुड़ने का अर्थ है अंत में विखंडू को जोड़ना / हटाना - चंक्स को ऊपर / नीचे शिफ्ट करने की कोई आवश्यकता नहीं है। मेमोरी रियलाइजेशन के कारण अभी भी नकल की आवश्यकता हो सकती है, लेकिन अक्सर नहीं।
यह प्रोसेसर के लिए कोई स्पष्ट प्रासंगिकता नहीं है, निश्चित रूप से - जब तक सीपीयू को हार्डवेयर बड़े-पूर्णांक समर्थन के साथ नहीं बनाया जाता है, यह विशुद्ध रूप से एक पुस्तकालय की चीज है।
किसी और ने जवाब नहीं दिया कि ऐसा क्यों किया जा सकता है, परिणामों के बारे में बहुत सारी चीजें।
एक 8 बिट प्रोसेसर पर विचार करें जो किसी दिए गए घड़ी चक्र में मेमोरी से एक सिंगल बाइट को लोड कर सकता है।
अब, यदि आप एक 16 बिट मान को लोड करना चाहते हैं, तो (कहें) आपके पास एक और केवल 16 बिट रजिस्टर है - अर्थात प्रोग्राम काउंटर, फिर इसे करने का एक सरल तरीका है:
परिणाम: आप केवल कभी-कभी लाने के स्थान को बढ़ाते हैं, आप केवल व्यापक रजिस्टर के कम क्रम वाले हिस्से में लोड करते हैं, और आपको केवल बाईं ओर शिफ्ट होने में सक्षम होना चाहिए। (बेशक, सही स्थानांतरण अन्य कार्यों के लिए सहायक है, इसलिए यह एक साइड शो का एक सा है।)
इसका एक परिणाम यह है कि 16 बिट (डबल बाइट) सामान मोस्ट..लीस्ट में स्टोर किया जाता है। यानी, छोटे पते में सबसे महत्वपूर्ण बाइट है - इतना बड़ा एंडियन।
यदि आपने इसके बजाय छोटे एंडियन का उपयोग करके लोड करने की कोशिश की है, तो आपको अपने विस्तृत रजिस्टर के निचले हिस्से में एक बाइट को लोड करने की आवश्यकता है, फिर अगले बाइट को एक स्टेजिंग क्षेत्र में लोड करें, इसे शिफ्ट करें, और फिर इसे अपने व्यापक रजिस्टर के शीर्ष में पॉप करें। । या फिर गेटिंग की एक अधिक जटिल व्यवस्था का उपयोग करके ऊपर या नीचे की बाइट में चुनिंदा लोड करने में सक्षम होने के लिए।
थोड़ा एंडियन जाने की कोशिश करने का नतीजा यह है कि आपको अधिक सिलिकॉन (स्विच और गेट्स), या अधिक संचालन की आवश्यकता है।
दूसरे शब्दों में, पुराने दिनों में हिरन के लिए बैंग होने के मामले में, आपको सबसे अधिक प्रदर्शन और सबसे छोटे सिलिकॉन क्षेत्र के लिए अधिक बैंग मिला।
इन दिनों, इन विचारों और काफी अप्रासंगिक है, लेकिन पाइप लाइन को भरने तरह बातें कर सकते हैं अभी भी एक बड़ी बात का एक सा हो।
जब एस / डब्ल्यू लिखने की बात आती है, तो छोटे एंडियन संबोधन का उपयोग करते समय जीवन अक्सर आसान होता है।
(और बड़ा एंडियन प्रोसेसर बाइट ऑर्डर करने के मामले में बड़ा एंडियन होता है और बिट-बाय-बाइट के मामले में थोड़ा एंडियन होता है। लेकिन कुछ प्रोसेसर अजीब होते हैं और बड़े एंडियन बिट ऑर्डर के साथ-साथ बाइट ऑर्डर भी करते हैं। यह जीवन को बहुत अच्छा बनाता है। एच / डब्ल्यू डिजाइनर के लिए दिलचस्प है मेमोरी-मैप्ड बाह्य उपकरणों को जोड़ना लेकिन प्रोग्रामर के लिए कोई अन्य परिणाम नहीं है।)
jimwise ने एक अच्छी बात की। एक और मुद्दा है, थोड़ा एंडियन में आप निम्न कार्य कर सकते हैं:
byte data[4];
int num=0;
for(i=0;i<4;i++)
num += data[i]<<i*8;
OR
num = *(int*)&data; //is interpreted as
mov dword data, num ;or something similar it has been some time
प्रोग्रामर के लिए अधिक सीधे फॉरवर्ड जो कि मेमोरी में स्वैप किए गए स्थानों के स्पष्ट नुकसान से प्रभावित नहीं हैं। मुझे व्यक्तिगत रूप से बड़ा एंडियन लगता है जो स्वाभाविक है का उलटा होना :)। 12 संग्रहीत और 21 के रूप में लिखा जाना चाहिए :)
for(i=0; i<4; i++) { num += data[i] << (24 - i * 8); }
से मेल खाती है move.l data, num
।
मुझे हमेशा आश्चर्य होता है कि कोई क्यों बाइट्स को रिवर्स ऑर्डर में स्टोर करना चाहेगा
दशमलव संख्या में बड़े एंडियन लिखे जाते हैं। यह भी है कि आप इसे अंग्रेजी में कैसे लिखते हैं आप सबसे महत्वपूर्ण अंक के साथ शुरू करते हैं और अगले सबसे महत्वपूर्ण से कम से कम सबसे महत्वपूर्ण। जैसे
1234
एक हजार, दो सौ चौंतीस है।
इस तरह से बड़े एंडियन को कभी-कभी प्राकृतिक क्रम कहा जाता है।
छोटे एंडियन में, यह संख्या एक, बीस, तीन सौ और चार हजार होगी।
हालांकि, जब आप अंकगणित जैसे जोड़ या घटाव करते हैं, तो आप अंत के साथ शुरू करते हैं।
1234
+ 0567
====
आप 4 और 7 से शुरू करते हैं, सबसे कम अंक लिखते हैं और कैरी को याद करते हैं। फिर आप 3 और 6 आदि जोड़ते हैं। ऐड, घटाना या तुलना के लिए, इसे लागू करना सरल है, यदि आपके पास पहले से ही मेमोरी को क्रम में पढ़ने के लिए तर्क है, यदि संख्याएं उलट हैं।
इस तरह से बड़े एंडियन का समर्थन करने के लिए, आपको मेमोरी को रिवर्स में पढ़ने के लिए तर्क की आवश्यकता होती है, या आपके पास आरआईएससी प्रक्रिया है जो केवल रजिस्टरों पर काम करती है। ;)
Intel x86 / Amd x64 डिज़ाइन का बहुत कुछ ऐतिहासिक है।
बिग-एंडियन कुछ ऑपरेशनों के लिए उपयोगी है (दिमाग के बराबर ऑक्टेट-लंबाई स्प्रिंग्स के "bignums" की तुलना)। दूसरों के लिए लिटिल-एंडियन (दो "bignums" जोड़कर, संभवतः)। अंत में, यह इस बात पर निर्भर करता है कि सीपीयू हार्डवेयर को किसके लिए स्थापित किया गया है, यह आमतौर पर एक या दूसरे (कुछ एमआइपी चिप्स थे, IIRC, LE या BE होने के लिए बूट पर उपलब्ध है)।
जब परिवर्तनशील लंबाई के साथ केवल भंडारण और स्थानांतरण शामिल होते हैं, लेकिन कई मानों के साथ कोई अंकगणित नहीं होता है, तो LE को आमतौर पर लिखना आसान होता है, जबकि BE को पढ़ना आसान होता है।
आइए एक विशिष्ट उदाहरण के रूप में एक इंट-टू-स्ट्रिंग रूपांतरण (और पीछे) लें।
int val_int = 841;
char val_str[] = "841";
जब इंट को स्ट्रिंग में परिवर्तित किया जाता है, तो सबसे महत्वपूर्ण अंक की तुलना में कम से कम महत्वपूर्ण अंक निकालना आसान होता है। यह सब एक साधारण लूप में किया जा सकता है जिसमें एक साधारण अंतिम स्थिति होती है।
val_int = 841;
// Make sure that val_str is large enough.
i = 0;
do // Write at least one digit to care for val_int == 0
{
// Constants, can be optimized by compiler.
val_str[i] = '0' + val_int % 10;
val_int /= 10;
i++;
}
while (val_int != 0);
val_str[i] = '\0';
// val_str is now in LE "148"
// i is the length of the result without termination, can be used to reverse it
अब BE ऑर्डर में भी यही कोशिश करें। आमतौर पर आपको एक और विभाजक की आवश्यकता होती है जो विशिष्ट संख्या (यहां 100) के लिए 10 की सबसे बड़ी शक्ति रखता है। आपको पहले इसे खोजने की आवश्यकता है, निश्चित रूप से। और भी बहुत कुछ करना है।
बीई में ऐसा करना आसान है, जब इसे रिवर्स राइट ऑपरेशन के रूप में किया जाता है। स्टोर को सबसे महत्वपूर्ण अंक पिछले लिखें, इसलिए इसे पहले पढ़ा जाना चाहिए।
val_int = 0;
length = strlen(val_str);
for (i = 0; i < length; i++)
{
// Again a simple constant that can be optimized.
val_int = 10*val_int + (val_str[i] - '0');
}
अब ले क्रम में भी ऐसा ही करें। फिर, आपको 1 से शुरू होने वाले अतिरिक्त कारक की आवश्यकता होगी और प्रत्येक अंक के लिए 10 से गुणा किया जाएगा।
इस प्रकार मैं आमतौर पर बीई को स्टोरेज के लिए इस्तेमाल करना पसंद करता हूं, क्योंकि एक वैल्यू एक बार ही लिखी जाती है, लेकिन कम से कम एक बार और शायद कई बार पढ़ी जाती है। इसकी सरल संरचना के लिए, मैं आमतौर पर ले को बदलने और फिर परिणाम को रिवर्स करने के लिए मार्ग जाता हूं, भले ही वह दूसरी बार मूल्य लिखता हो।
BE भंडारण के लिए एक और उदाहरण UTF-8 एन्कोडिंग होगा, और कई और।