C ++ प्रोग्राम में प्रोग्रामेटिक रूप से एंडियननेस का पता लगाना


211

क्या यह पता लगाने का एक प्रोग्रामेटिक तरीका है कि आप बड़े-एंडियन या छोटे-एंडियन आर्किटेक्चर पर हैं या नहीं? मुझे ऐसा कोड लिखने में सक्षम होना चाहिए जो इंटेल या पीपीसी सिस्टम पर अमल करेगा और ठीक उसी कोड (यानी कोई सशर्त कंप्लेन) का उपयोग नहीं करेगा।


4
संपूर्णता की खातिर, यहां किसी और के सवाल का एक लिंक दिया गया है कि वह धीरज धरने की कोशिश कर रहा है (संकलन के समय): stackoverflow.com/questions/280162/…
फैसल वली

14
संकलन-समय पर धीरज का निर्धारण क्यों नहीं? यह संभवतः रनटाइम में नहीं बदल सकता है।
इफिशिएंट

3
AFAIK, ऐसा करने के लिए कोई विश्वसनीय और सार्वभौमिक तरीका नहीं है। gcc.gnu.org/ml/gcc-help/2007-07/msg00342.html
user48956

जवाबों:


174

मुझे टाइप पाइंटिंग पर आधारित विधि पसंद नहीं है - यह अक्सर कंपाइलर के खिलाफ चेतावनी दी जाएगी। यही तो यूनियनों के लिए है!

bool is_big_endian(void)
{
    union {
        uint32_t i;
        char c[4];
    } bint = {0x01020304};

    return bint.c[0] == 1; 
}

सिद्धांत अन्य लोगों द्वारा सुझाए गए प्रकार के मामले के बराबर है, लेकिन यह स्पष्ट है - और C99 के अनुसार, सही होने की गारंटी है। प्रत्यक्ष सूचक की तुलना में gcc इसे पसंद करता है।

यह संकलन समय पर एंडियननेस को ठीक करने से भी बेहतर है - ओएस के लिए जो मल्टी-आर्किटेक्चर (उदाहरण के लिए मैक ओएस एक्स पर वसा बाइनरी) का समर्थन करते हैं, यह दोनों पीपीसी / i386 के लिए काम करेगा, जबकि चीजों को गड़बड़ाना बहुत आसान है अन्यथा ।


51
मैं एक चर "बिंट" नामकरण की सिफारिश नहीं करता हूं :)
mkb

42
क्या आप सुनिश्चित हैं कि यह अच्छी तरह से परिभाषित है? C ++ में संघ का केवल एक ही सदस्य एक समय में सक्रिय हो सकता है - यानी आप एक सदस्य का नाम उपयोग करके असाइन नहीं कर सकते हैं और दूसरे का उपयोग करके पढ़ सकते हैं (हालांकि लेआउट संगत संरचनाओं के लिए एक अपवाद है)
फैसल वली

27
@ मैट: मैंने Google में देखा, और लगता है कि अंग्रेजी में एक अर्थ है कि मुझे इसके बारे में पता नहीं था :)
डेविड कोर्टन्यू

17
मैंने इसका परीक्षण किया है, और gcc 4.0.1 और gcc 4.4.1 दोनों में, इस फ़ंक्शन का परिणाम संकलन समय पर निर्धारित किया जा सकता है और इसे स्थिर माना जाता है। इसका मतलब यह है कि संकलक छोड़ देगा यदि शाखाएं जो केवल इस फ़ंक्शन के परिणाम पर निर्भर करती हैं और कभी भी प्रश्न में मंच पर नहीं ली जाएंगी। यह संभवतः htonl के कई कार्यान्वयनों का सच नहीं है।
सर्वव्यापी

6
क्या यह समाधान वास्तव में पोर्टेबल है? क्या होगा अगर CHAR_BIT != 8?
जोर्जेट

80

आप इसे एक इंट और मास्किंग ऑफ बिट्स सेट करके कर सकते हैं, लेकिन शायद सबसे आसान तरीका बिल्ट इन नेटवर्क बाइट कन्वर्जन ऑप्स (चूंकि नेटवर्क बाइट ऑर्डर हमेशा बड़ा एंडियन है) का उपयोग करना है।

if ( htonl(47) == 47 ) {
  // Big endian
} else {
  // Little endian.
}

बिट फ़िडलिंग तेज़ हो सकती है, लेकिन यह तरीका सरल, सीधा और गड़बड़ करने के लिए बहुत असंभव है।


1
नेटवर्क रूपांतरण ऑप्स का उपयोग सब कुछ बड़े एंडियन में परिवर्तित करने के लिए भी किया जा सकता है, इस प्रकार अन्य समस्याओं को हल करने में जे का सामना हो सकता है।
ब्रायन

6
@ साभार - धीमी गति एक सापेक्ष शब्द है, लेकिन हां, अगर गति वास्तव में एक मुद्दा है, तो प्रोग्राम की शुरुआत में एक बार इसका उपयोग करें और धीरज के साथ एक वैश्विक चर सेट करें।
एरिक पेट्रोलेजे

5
htonl में एक और समस्या है: कुछ प्लेटफार्मों (विंडोज़?) पर, यह उचित रूप से C रनटाइम लाइब्रेरी में नहीं रहता है, लेकिन अतिरिक्त में, नेटवर्क से संबंधित लाइब्रेरी (सॉकेट, आदि ...)। यह सिर्फ एक समारोह के लिए काफी बाधा है अगर आपको अन्यथा पुस्तकालय की आवश्यकता नहीं है।
डेविड कर्टनपो जुले

7
ध्यान दें कि लिनक्स (gcc) पर, htonl संकलन समय पर लगातार फोल्डिंग के अधीन है, इसलिए इस फॉर्म के एक्सप्रेशन में कोई रनटाइम ओवरहेड नहीं है (अर्थात यह लगातार 1 या 0 से मुड़ा हुआ है, और फिर डेड-कोड एलिमिनेशन हटाता है
इफ

2
इसके अलावा, x86 htonl पर (और लिनक्स / gcc पर) इनलाइन असेंबलर का उपयोग करके बहुत कुशलता से लागू किया जा सकता है, खासकर यदि आप BSWAPऑपरेशन के लिए समर्थन के साथ एक माइक्रो-आर्किटेक्चर को लक्षित करते हैं ।
बोनालन

61

कृपया इस लेख को देखें :

आपकी मशीन का प्रकार क्या है, यह निर्धारित करने के लिए यहां कुछ कोड दिए गए हैं

int num = 1;
if(*(char *)&num == 1)
{
    printf("\nLittle-Endian\n");
}
else
{
    printf("Big-Endian\n");
}

25
ध्यान रखें कि यह इंट और चार अलग लंबाई होने पर निर्भर करता है, जो लगभग हमेशा ही होता है लेकिन इसकी गारंटी नहीं होती है।
डेविड थॉर्नले

10
मैंने एम्बेडेड सिस्टम पर काम किया है जहाँ शॉर्ट इंट और चार समान आकार थे ... मुझे याद नहीं है कि नियमित इंट उस आकार (2 बाइट्स) का भी था या नहीं।
rmeador

2
ऐसा क्यों है, जो केवल इतना ही जवाब नहीं दे रहा है कि मुझे नहीं लगता कि "यार, wtf तुम कर रहे हो?", जो यहाँ के अधिकांश उत्तरों का मामला है: o
hanshenrik

2
@ साइलार्ड इंट कम से कम इतना बड़ा होना चाहिए, लेकिन मानक में कोई आवश्यकता नहीं है कि चार को कम तक सीमित किया जाए! यदि आप TI F280x परिवार पर एक नज़र डालते हैं, तो आपको पता चलेगा कि CHAR_BIT 16 है और sizeof (int) == sizeof (char) जबकि आपके द्वारा उल्लिखित सीमाएँ बिल्कुल ठीक रखी गई हैं ...
Aconcagua

5
Uint8_t और uint16_t का उपयोग क्यों नहीं किया जाता है?
रॉड्रिगो

58

std::endianयदि आपके पास C ++ 20 कंपाइलर जैसे GCC 8+ या Clang 7+ का उपयोग है, तो आप इसका उपयोग कर सकते हैं ।

नोट: std::endianमें शुरू हुआ <type_traits>लेकिन ले जाया गया था करने के लिए <bit>2019 कोलोन बैठक में। GCC 8, Clang 7, 8 और 9 के पास है <type_traits>जबकि GCC 9+ और Clang में 10+ है <bit>

#include <bit>

if constexpr (std::endian::native == std::endian::big)
{
    // Big endian system
}
else if constexpr (std::endian::native == std::endian::little)
{
    // Little endian system
}
else
{
    // Something else
}

5
जैसा कि सभी के पास C ++ 17 और 20 ड्राफ्ट / प्रस्ताव हैं, लेकिन अब तक, क्या कोई C ++ 20 कंपाइलर कभी मौजूद है?
Xeverous

@Xeverous इसे केवल स्कूप्ड एनुमरेशन्स की आवश्यकता होती है, इसलिए मुझे संदेह है कि अधिकांश विक्रेता इसे अपने पहले के परिवर्तनों के रूप में अपने stdlib कार्यान्वयन में जोड़ देंगे।
फराप

@ Xeverous GCC 8 जारी किया गया था और इसका समर्थन करता है।
लिबर्टा

प्रश्न के 30+ उत्तरों में से, यह केवल एक ही प्रतीत होता है, यह पूरी तरह से सटीक है (दूसरे उत्तर के साथ जो कम से कम भाग में सही है)।
IInspectable

40

यह आम तौर पर संकलनकर्ता से उपलब्ध हेडर फ़ाइलों का उपयोग करके या अपना स्वयं का निर्माण करके संकलन समय (विशेष रूप से प्रदर्शन के कारण) पर किया जाता है। लिनक्स पर आपके पास हेडर फ़ाइल "/usr/include/endian.h" है


8
मैं विश्वास नहीं कर सकता कि यह उच्च मतदान नहीं किया गया है। यह ऐसा नहीं है कि संकलित कार्यक्रम के तहत अंतरण में परिवर्तन होने वाला है, इसलिए रनटाइम टेस्ट की कोई आवश्यकता नहीं है।
Dolda2000

@ Dolda2000 यह संभवतः एआरएम एंडियन मोड को देख सकता है।
टाइजॉइड

10
@ टायज़ॉइड: नहीं, एक संकलित कार्यक्रम हमेशा एंडियन मोड के तहत चलेगा, जिसके लिए संकलित किया गया था, भले ही प्रोसेसर या तो सक्षम हो।
डोडा २२

16

मुझे आश्चर्य हुआ कि किसी ने भी मैक्रोज़ का उल्लेख नहीं किया है जो कि पूर्व-प्रोसेसर डिफ़ॉल्ट रूप से परिभाषित करता है। जबकि ये आपके प्लेटफॉर्म के आधार पर अलग-अलग होंगे; वे अपने स्वयं के एंडियन-चेक लिखने की तुलना में बहुत साफ हैं।

उदाहरण के लिए; यदि हम अंतर्निहित मैक्रोज़ को देखते हैं जो GCC परिभाषित करता है (X86-64 मशीन पर):

:| gcc -dM -E -x c - |grep -i endian
#define __LITTLE_ENDIAN__ 1

एक पीपीसी मशीन पर मुझे मिलता है:

:| gcc -dM -E -x c - |grep -i endian
#define __BIG_ENDIAN__ 1
#define _BIG_ENDIAN 1

( :| gcc -dM -E -x c -जादू सभी अंतर्निहित मैक्रोज़ को प्रिंट करता है)।


7
ये मैक्रोज़ लगातार दिखाई नहीं देते हैं। उदाहरण के लिए, Redhat 6 रेपो से gcc 4.4.5 में, echo "\n" | gcc -x c -E -dM - |& grep -i 'endian'रिटर्न कुछ नहीं चल रहा है, जबकि /usr/sfw/binSolaris में gcc 3.4.3 ( वैसे भी) इन पंक्तियों के साथ एक परिभाषा है। मैंने VxWorks Tornado (gcc 2.95) -vs- VxWorks Workbench (gcc 3.4.4) पर इसी तरह के मुद्दे देखे हैं।
ब्रायन वंडेनबर्ग सेप

15

एहम ... मुझे आश्चर्य है कि किसी ने महसूस नहीं किया है कि कंपाइलर केवल टेस्ट आउट का अनुकूलन करेगा, और रिटर्न वैल्यू के रूप में एक निश्चित परिणाम देगा। यह उपरोक्त सभी कोड उदाहरणों को प्रस्तुत करता है, प्रभावी रूप से बेकार। केवल एक चीज जो वापस लौटा दी जाएगी, वह संकलन-समय पर अंतःकरण है! और हाँ, मैंने उपरोक्त सभी उदाहरणों का परीक्षण किया। यहाँ MSVC 9.0 (विजुअल स्टूडियो 2008) के साथ एक उदाहरण दिया गया है।

शुद्ध C कोड

int32 DNA_GetEndianness(void)
{
    union 
    {
        uint8  c[4];
        uint32 i;
    } u;

    u.i = 0x01020304;

    if (0x04 == u.c[0])
        return DNA_ENDIAN_LITTLE;
    else if (0x01 == u.c[0])
        return DNA_ENDIAN_BIG;
    else
        return DNA_ENDIAN_UNKNOWN;
}

disassembly

PUBLIC  _DNA_GetEndianness
; Function compile flags: /Ogtpy
; File c:\development\dna\source\libraries\dna\endian.c
;   COMDAT _DNA_GetEndianness
_TEXT   SEGMENT
_DNA_GetEndianness PROC                 ; COMDAT

; 11   :     union 
; 12   :     {
; 13   :         uint8  c[4];
; 14   :         uint32 i;
; 15   :     } u;
; 16   : 
; 17   :     u.i = 1;
; 18   : 
; 19   :     if (1 == u.c[0])
; 20   :         return DNA_ENDIAN_LITTLE;

    mov eax, 1

; 21   :     else if (1 == u.c[3])
; 22   :         return DNA_ENDIAN_BIG;
; 23   :     else
; 24   :        return DNA_ENDIAN_UNKNOWN;
; 25   : }

    ret
_DNA_GetEndianness ENDP
END

शायद इस फ़ंक्शन के लिए किसी भी संकलन-समय अनुकूलन को बंद करना संभव है, लेकिन मुझे नहीं पता। अन्यथा विधानसभा में इसे हार्डकोड करना संभव है, हालांकि यह पोर्टेबल नहीं है। और तब भी कि बाहर अनुकूलित हो सकता है। यह मुझे लगता है कि मुझे कुछ वास्तव में भद्दे असेंबलर की आवश्यकता है, सभी मौजूदा सीपीयू / निर्देश सेटों के लिए समान कोड लागू करें, और अच्छी तरह से .... कभी भी बुरा मत मानना।

साथ ही, यहां किसी ने कहा कि रन-टाइम के दौरान एंडियनेस नहीं बदलता है। गलत। वहां पर बाय-एंडियन मशीनें हैं। उनकी अंत्येष्टि में डर्ंग निष्पादन अलग-अलग हो सकता है। इसके अलावा, न केवल लिटिल एंडियन और बिग एंडियन हैं, बल्कि अन्य एंडियननेस (एक शब्द भी) है।

मुझे नफरत है और एक ही समय में कोडिंग से प्यार है ...


11
क्या आपको किसी अन्य प्लेटफ़ॉर्म पर वैसे भी चलने के लिए recompile नहीं करना है?
bobobobo

2
यद्यपि यह MSVC के लिए अच्छा काम करता है, यह सभी परिस्थितियों में सभी GCC संस्करण के लिए नहीं है। इसलिए, एक महत्वपूर्ण लूप के अंदर "रन-टाइम चेक" संकलन-समय पर सही ढंग से अन-ब्रांच किया जा सकता है, या नहीं। कोई 100% गारंटी नहीं है।
सियान

21
बड़े-एंडियन x86 प्रोसेसर जैसी कोई चीज नहीं है। यहां तक ​​कि अगर आप एक बायेंडियन प्रोसेसर (जैसे एआरएम या एमआईपीएस) पर उबंटू चलाते हैं, तो ईएलएफ निष्पादन हमेशा या तो बड़े (एमएसबी) या छोटे (एलएसबी) एंडियन होते हैं। कोई भी बेंडियन निष्पादनयोग्य नहीं बनाया जा सकता है, इसलिए रनटाइम चेक की आवश्यकता नहीं है।
फाबेल

4
इस विधि में अनुकूलन को बंद करने के लिए 'वाष्पशील संघ ...' का उपयोग करें यह संकलक को बताता है कि 'u' को कहीं और बदला जा सकता है और डेटा लोड किया जाना चाहिए
mishmashru

1
इस फ़ंक्शन के लिए ऑप्टिमाइज़र की तुलना में रनटाइम पर एक अलग मान वापस करने के लिए गणना कर रहा है कि यह आशय है कि ऑप्टिमाइज़र को रोक दिया गया है। क्या आप कह रहे हैं कि संकलित अनुकूलित बाइनरी कोड के उदाहरण हैं, जो संकलन के दौरान ऑप्टिमाइज़र (कार्यक्रम के दौरान) द्वारा बनाई गई स्पष्ट धारणाओं के बावजूद, जो अलग-अलग धीरज के दो अलग-अलग आर्किटेक्चर पर चल सकते हैं, कम से कम उन में से एक के साथ असंगत प्रतीत होंगे। आर्किटेक्चर?
स्कॉट

13

एक अंतर चर घोषित करें:

int variable = 0xFF;

अब इसके विभिन्न भागों में चार * बिंदुओं का उपयोग करें और जाँचें कि उन भागों में क्या है।

char* startPart = reinterpret_cast<char*>( &variable );
char* endPart = reinterpret_cast<char*>( &variable ) + sizeof( int ) - 1;

जिसके आधार पर 0xFF बाइट पर एक अंक अब आप एंडियननेस का पता लगा सकते हैं। इसके लिए sizeof (int)> sizeof (char) की आवश्यकता होती है, लेकिन चर्चा किए गए प्लेटफ़ॉर्म के लिए यह निश्चित रूप से सही है।


8

अधिक जानकारी के लिए, तुम बाहर इस codeproject लेख भी देखना चाहें endianness पर बुनियादी अवधारणाओं :

रन टाइम में एंडियन प्रकार के लिए गतिशील परीक्षण कैसे करें?

जैसा कि कंप्यूटर एनिमेशन एफएक्यू में बताया गया है, आप निम्न फ़ंक्शन का उपयोग यह देखने के लिए कर सकते हैं कि आपका कोड थोड़ा- या बिग-एंडियन सिस्टम पर चल रहा है या नहीं: संक्षिप्त करें

#define BIG_ENDIAN      0
#define LITTLE_ENDIAN   1
int TestByteOrder()
{
   short int word = 0x0001;
   char *byte = (char *) &word;
   return(byte[0] ? LITTLE_ENDIAN : BIG_ENDIAN);
}

यह कोड 0001h को 16-बिट पूर्णांक को असाइन करता है। एक चर सूचक तब पूर्णांक मान के पहले (सबसे कम-महत्वपूर्ण) बाइट पर इंगित करने के लिए असाइन किया गया है। यदि पूर्णांक का पहला बाइट 0x01h है, तो सिस्टम लिटिल-एंडियन है (0x01h निम्नतम, या कम से कम महत्वपूर्ण, पते में है)। यदि यह 0x00h है तो सिस्टम बिग-एंडियन है।


6

C ++ तरीका बूस्ट का उपयोग करने के लिए किया गया है , जहां प्रीप्रोसेसर चेक और कास्ट को बहुत अच्छी तरह से परीक्षण किए गए पुस्तकालयों के अंदर कंपार्टमेंटलाइज़ किया गया है।

प्रीडिफ लाइब्रेरी (बूस्ट / प्रिफ.एच) चार अलग-अलग प्रकार के एंडियननेस को पहचानता है ।

एन्डियन लाइब्रेरी सी ++ मानक को प्रस्तुत करने की योजना है, और endian के प्रति संवेदनशील डेटा पर कार्रवाई की एक विस्तृत विविधता का समर्थन करता है किया गया था।

जैसा कि ऊपर दिए गए जवाबों में कहा गया है, एंडियननेस c ++ 20 का एक हिस्सा होगा।


1
FYI करें, "चार अलग-अलग प्रकार के धीरज" लिंक टूटा है,
रेमी लेबेऊ

फिक्स्ड और बनाया विकी
fuzzyTew

5

जब तक आप एक ऐसे फ्रेमवर्क का उपयोग नहीं कर रहे हैं जिसे PPC और Intel प्रोसेसर में पोर्ट किया गया है, तो आपको सशर्त संकलन करना होगा, क्योंकि PPC और Intel प्लेटफ़ॉर्म में पूरी तरह से अलग-अलग हार्डवेयर आर्किटेक्चर, पाइपलाइन, busses इत्यादि हैं। यह असेंबली कोड को पूरी तरह से बीच में रेंडर करता है दो।

एंडियननेस खोजने के लिए, निम्न कार्य करें:

short temp = 0x1234;
char* tempChar = (char*)&temp;

आपको या तो टेम्परेचर 0x12 या 0x34 मिलेगा, जिससे आप एंडियननेस जान पाएंगे।


3
यह ठीक 2 बाइट्स पर निर्भर करता है जिसकी गारंटी नहीं है।
शार्पटूट

3
हालांकि यह प्रश्न में दिए गए दो आर्किटेक्चर पर आधारित एक बहुत ही सुरक्षित शर्त होगी।
डेमिन

8
दूसरे प्लेटफ़ॉर्म पर अलग-अलग होने के विरुद्ध भविष्य के प्रमाण को शामिल करें stdint.hऔर int16_tउसका उपयोग करें ।
डेनिस स्किडमोर

4

मैं ऐसा कुछ करूंगा:

bool isBigEndian() {
    static unsigned long x(1);
    static bool result(reinterpret_cast<unsigned char*>(&x)[0] == 0);
    return result;
}

इन पंक्तियों के साथ, आपको एक समय कुशल फ़ंक्शन मिलेगा जो केवल एक बार गणना करता है।


क्या आप इसे इनलाइन कर सकते हैं? निश्चित नहीं है कि अगर इनलाइन स्टैटिक वैरिएबल के कई मेमोरी ब्लॉक का कारण
बनती है

4

जैसा कि ऊपर कहा गया है, संघ चाल का उपयोग करें।

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

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

#include <stdint.h>

#define BIG_ENDIAN 1
#define LITTLE_ENDIAN 0

template <typename T>
T endian(T w, uint32_t endian)
{
    // this gets optimized out into if (endian == host_endian) return w;
    union { uint64_t quad; uint32_t islittle; } t;
    t.quad = 1;
    if (t.islittle ^ endian) return w;
    T r = 0;

    // decent compilers will unroll this (gcc)
    // or even convert straight into single bswap (clang)
    for (int i = 0; i < sizeof(r); i++) {
        r <<= 8;
        r |= w & 0xff;
        w >>= 8;
    }
    return r;
};

उपयोग:

दिए गए एंडियन से होस्ट में बदलने के लिए, उपयोग करें:

host = endian(source, endian_of_source)

होस्ट एंडियन से दिए गए एंडियन में बदलने के लिए, उपयोग करें:

output = endian(hostsource, endian_you_want_to_output)

परिणामी कोड क्लैंग पर हाथ की असेंबली लिखने के रूप में तेज़ है, जीसीसी पर यह धीमी (अनियंत्रित और; <<, >>, हर बाइट के लिए) है, लेकिन अभी भी सभ्य है।



4

का उपयोग न करें union!

सी ++ unionएस के माध्यम से टाइपिंग की अनुमति नहीं देता है !
एक संघ क्षेत्र से पढ़ना, जो अपरिभाषित व्यवहार के लिए लिखा गया अंतिम क्षेत्र नहीं था !
कई संकलक एक एक्सटेंशन के रूप में ऐसा करने का समर्थन करते हैं, लेकिन भाषा कोई गारंटी नहीं देती है।

अधिक विवरण के लिए यह उत्तर देखें:

https://stackoverflow.com/a/11996970


केवल दो मान्य उत्तर हैं जो पोर्टेबल होने की गारंटी है।

पहला उत्तर, यदि आपके पास C ++ 20 का समर्थन करने वाले सिस्टम तक पहुंच है, तो हेडर से
उपयोग करना std::endianहै <type_traits>

(लेखन के समय, C ++ 20 को अभी तक जारी नहीं किया गया है, लेकिन जब तक कि कुछ शामिल होने को प्रभावित नहीं करता है std::endian, यह C ++ 20 के बाद के संकलन समय पर अंतरण का परीक्षण करने का पसंदीदा तरीका होगा।)

C ++ 20 आगे

constexpr bool is_little_endian = (std::endian::native == std::endian::little);

C ++ 20 से पहले, एकमात्र मान्य उत्तर पूर्णांक को संग्रहीत करना और फिर टाइप पाइंटिंग के माध्यम से इसके पहले बाइट का निरीक्षण करना है। S
के उपयोग के विपरीत union, यह स्पष्ट रूप से C ++ के टाइप सिस्टम द्वारा अनुमत है।

यह भी याद रखना महत्वपूर्ण है कि इष्टतम पोर्टेबिलिटी के static_castलिए उपयोग किया जाना चाहिए,
क्योंकि reinterpret_castकार्यान्वयन को परिभाषित किया गया है।

यदि कोई प्रोग्राम किसी वस्तु के संग्रहित मूल्य को निम्न प्रकार के व्यवहार के अलावा किसी अन्य वस्तु के ग्लव्यू के माध्यम से एक्सेस करने का प्रयास करता है तो व्यवहार अपरिभाषित है: ... charया एक unsigned charप्रकार।

C ++ 11 आगे

enum class endianness
{
    little = 0,
    big = 1,
};

inline endianness get_system_endianness()
{
    const int value { 0x01 };
    const void * address = static_cast<const void *>(&value);
    const unsigned char * least_significant_address = static_cast<const unsigned char *>(address);
    return (*least_significant_address == 0x01) ? endianness::little : endianness::big;
}

C ++ 11 आगे (बिना एनम)

inline bool is_system_little_endian()
{
    const int value { 0x01 };
    const void * address = static_cast<const void *>(&value);
    const unsigned char * least_significant_address = static_cast<const unsigned char *>(address);
    return (*least_significant_address == 0x01);
}

सी ++ 98 / सी ++ 03

inline bool is_system_little_endian()
{
    const int value = 0x01;
    const void * address = static_cast<const void *>(&value);
    const unsigned char * least_significant_address = static_cast<const unsigned char *>(address);
    return (*least_significant_address == 0x01);
}

3
union {
    int i;
    char c[sizeof(int)];
} x;
x.i = 1;
if(x.c[0] == 1)
    printf("little-endian\n");
else    printf("big-endian\n");

यह एक और उपाय है। एंड्रयू हरे के समाधान के समान।


3

निष्कलंक, लेकिन मेरे दिमाग में, यह काम करना चाहिए? क्योंकि यह छोटे एंडियन पर 0x01 और बड़े एंडियन पर 0x00 होगा?

bool runtimeIsLittleEndian(void)
{
 volatile uint16_t i=1;
 return  ((uint8_t*)&i)[0]==0x01;//0x01=little, 0x00=big
}

3

घोषित:

मेरी प्रारंभिक पोस्ट को "संकलन समय" के रूप में गलत रूप से घोषित किया गया है। यह नहीं है, यह वर्तमान सी ++ मानक में भी असंभव है। कॉन्स्टैक्स का मतलब यह नहीं है कि फ़ंक्शन हमेशा संकलन-समय की गणना करता है। धन्यवाद सुधार के लिए रिचर्ड होजेस।

संकलित समय, गैर-मैक्रो, C ++ 11 कॉन्स्ट्रेप समाधान:

union {
  uint16_t s;
  unsigned char c[2];
} constexpr static  d {1};

constexpr bool is_little_endian() {
  return d.c[0] == 1;
}

2
क्या आपने uint8_t पर अहस्ताक्षरित चार का उपयोग किया है?
केविन

0 रनटाइम ओवरहेड ... मुझे यह पसंद है!
1

मुझे लगता है, यह निर्माण मशीन के एंडियन का पता लगाता है, न कि लक्ष्य?
12

2
क्या यह UB C ++ में नहीं है?
rr-

6
यह कानूनी संदर्भ में कानूनी नहीं है। आप एक ऐसे संघ के सदस्य तक नहीं पहुँच सकते हैं जो सीधे आरंभीकृत नहीं किया गया है। प्रीप्रोसेसर जादू के बिना संकलित समय पर कानूनी रूप से धीरज का पता लगाने का कोई तरीका नहीं है।
रिचर्ड होजेस

2

आप इसे प्रीप्रोसेसर के माध्यम से बूस्टर हेडर फ़ाइल जैसी कुछ चीज़ों का उपयोग करके भी कर सकते हैं जिसे बूस्ट एंडियन पाया जा सकता है


1

जब तक एंडियन हेडर जीसीसी-ओनली नहीं होता है, तब तक यह मैक्रो प्रदान करता है जिसका आप उपयोग कर सकते हैं।

#include "endian.h"
...
if (__BYTE_ORDER == __LITTLE_ENDIAN) { ... }
else if (__BYTE_ORDER == __BIG_ENDIAN) { ... }
else { throw std::runtime_error("Sorry, this version does not support PDP Endian!");
...

ये नहीं हैं __BYTE_ORDER__, __ORDER_LITTLE_ENDIAN__और __ORDER_BIG_ENDIAN__?
Xeverous

1

यदि आप सशर्त संकलन नहीं चाहते हैं तो आप केवल एंडियन स्वतंत्र कोड लिख सकते हैं। यहाँ एक उदाहरण है ( रोब पाइक से लिया गया है ):

एंडियन स्वतंत्र तरीके से डिस्क पर लिटिल-एंडियन में संग्रहीत पूर्णांक को पढ़ना:

i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);

एक ही कोड, मशीन एंडियननेस को ध्यान में रखने की कोशिश कर रहा है:

i = *((int*)data);
#ifdef BIG_ENDIAN
/* swap the bytes */
i = ((i&0xFF)<<24) | (((i>>8)&0xFF)<<16) | (((i>>16)&0xFF)<<8) | (((i>>24)&0xFF)<<0);
#endif

कितना अच्छा विचार है! और अब अपने पूर्णांक को नेटवर्क सॉकेट के माध्यम से अज्ञात डिवाइस में स्थानांतरित करते हैं।
मैक्जिम गेनेंको

@MaksymGanenko मुझे आपकी टिप्पणी नहीं मिली। क्या यह विडंबना है? मैं सिलसिलेवार डेटा की समाप्ति को निर्दिष्ट नहीं करने का सुझाव नहीं दे रहा हूं । मैं डेटा प्राप्त करने वाली मशीन की समाप्ति पर निर्भर कोड नहीं लिखने का सुझाव दे रहा हूं।
fjardon

@MaksymGanenko यदि आप डाउनवोट करते हैं, तो आप बता सकते हैं कि उत्तर गलत क्यों है। कम से कम संभावित पाठकों को यह समझने में मदद करने के लिए कि उन्हें मेरे उत्तर का पालन क्यों नहीं करना चाहिए।
fjardon


0

इस बारे में कैसा है?

#include <cstdio>

int main()
{
    unsigned int n = 1;
    char *p = 0;

    p = (char*)&n;
    if (*p == 1)
        std::printf("Little Endian\n");
    else 
        if (*(p + sizeof(int) - 1) == 1)
            std::printf("Big Endian\n");
        else
            std::printf("What the crap?\n");
    return 0;
}

0

यहाँ एक और सी संस्करण है। यह wicked_cast()C99 यूनियन शाब्दिक और गैर-मानक __typeof__ऑपरेटर के माध्यम से इनलाइन प्रकार के लिए बुलाया मैक्रो को परिभाषित करता है ।

#include <limits.h>

#if UCHAR_MAX == UINT_MAX
#error endianness irrelevant as sizeof(int) == 1
#endif

#define wicked_cast(TYPE, VALUE) \
    (((union { __typeof__(VALUE) src; TYPE dest; }){ .src = VALUE }).dest)

_Bool is_little_endian(void)
{
    return wicked_cast(unsigned char, 1u);
}

यदि पूर्णांक एकल-बाइट मान हैं, तो धीरज का कोई मतलब नहीं है और एक संकलन-समय त्रुटि उत्पन्न होगी।


0

जिस तरह से सी compilers (कम से कम हर किसी पर मैं के बारे में पता) endianness काम है संकलन समय पर निर्णय लिया जाना है। यहां तक ​​कि बायेंडियन प्रोसेसर (जैसे एआरएम ऑक एमआईपीएस) के लिए आपको संकलन समय पर धीरज चुनना होगा। इसके अलावा निष्पादन योग्यताओं (जैसे ईएलएफ) के लिए सभी सामान्य फ़ाइल स्वरूपों में अधिक धीरज को परिभाषित किया गया है। यद्यपि यह बाइनरी कोड के बाइनरी ब्लॉब को शिल्प करना संभव है (कुछ एआरएम सर्वर शोषण के लिए?) यह शायद विधानसभा में किया जाना है।


-1

जैसा कि धनिया द्वारा कहा गया है, यहां उन कोड्स के अधिकांश (यदि सभी नहीं) संकलन समय पर दूर हो जाएंगे, तो उत्पन्न बायनेरिज़ रन समय पर "एंडियननेस" की जांच नहीं करेंगे।

यह देखा गया है कि किसी दिए गए निष्पादन योग्य को दो अलग-अलग बाइट क्रमों में नहीं चलना चाहिए, लेकिन मुझे पता नहीं है कि क्या हमेशा ऐसा होता है, और ऐसा लगता है कि संकलन समय पर मुझे हैक करना पसंद है। इसलिए मैंने इस फ़ंक्शन को कोडित किया:

#include <stdint.h>

int* _BE = 0;

int is_big_endian() {
    if (_BE == 0) {
        uint16_t* teste = (uint16_t*)malloc(4);
        *teste = (*teste & 0x01FE) | 0x0100;
        uint8_t teste2 = ((uint8_t*) teste)[0];
        free(teste);
        _BE = (int*)malloc(sizeof(int));
        *_BE = (0x01 == teste2);
    }
    return *_BE;
}

MinGW इस कोड को ऑप्टिमाइज़ करने में सक्षम नहीं था, भले ही यह अन्य कोड्स को यहाँ से ऑप्टिमाइज़ करता हो। मेरा मानना ​​है कि ऐसा इसलिए है क्योंकि मैं "बेतरतीब" मूल्य को छोड़ देता हूं जो कि छोटी बाइट मेमोरी पर अलग किया गया था जैसा कि यह था (कम से कम 7 बिट्स), इसलिए कंपाइलर यह नहीं जान सकता है कि यादृच्छिक मूल्य क्या है और यह अनुकूलन नहीं करता है समारोह दूर।

मैंने फ़ंक्शन को भी कोडित किया है ताकि चेक केवल एक बार किया जाए, और अगले परीक्षण के लिए वापसी मूल्य संग्रहीत किया जाता है।


2-बाइट मान पर काम करने के लिए 4 बाइट्स क्यों आवंटित करें? क्यों एक अनिश्चित मूल्य के साथ मुखौटा 0x7FE? आखिर क्यों इस्तेमाल करें malloc()? वह बेकार है। और _BEएक (यद्यपि छोटा) स्मृति रिसाव और एक दौड़ की स्थिति होने की प्रतीक्षा कर रहा है, परिणाम को गतिशील रूप से कैशिंग करने के लाभ परेशानी के लायक नहीं हैं। मैं इसके बजाय कुछ और करना चाहूंगा: static const uint16_t teste = 1; int is_little_endian() { return (0x01 == ((uint8_t*)&teste)[0]); } int is_big_endian() { return (0x01 == ((uint8_t*)&teste)[1]); }सरल और प्रभावी, और रनटाइम में प्रदर्शन करने के लिए बहुत कम काम।
रेमी लेबेउ

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

@TexKiller फिर कोड के लिए अनुकूलन को अक्षम क्यों नहीं किया? प्रयोग volatile, या #pragma, आदि
रेमी लेबू

@RemyLebeau, मैं उस समय उन कीवर्ड्स को नहीं जानता था, और मैंने जो कुछ भी जाना था उसके साथ कंपाइलर ऑप्टिमाइज़ेशन को रोकने के लिए मैंने इसे थोड़ी चुनौती के रूप में लिया।
टेक्स किलर

-1

इसे निर्धारित करने का कोई त्वरित और मानक तरीका नहीं है, यह इसे आउटपुट करेगा:

#include <stdio.h> 
int main()  
{ 
   unsigned int i = 1; 
   char *c = (char*)&i; 
   if (*c)     
       printf("Little endian"); 
   else
       printf("Big endian"); 
   getchar(); 
   return 0; 
} 

-1

एंडियनस देखें - सी-लेवल कोड चित्रण।

// assuming target architecture is 32-bit = 4-Bytes
enum ENDIANNESS{ LITTLEENDIAN , BIGENDIAN , UNHANDLE };


ENDIANNESS CheckArchEndianalityV1( void )
{
    int Endian = 0x00000001; // assuming target architecture is 32-bit    

    // as Endian = 0x00000001 so MSB (Most Significant Byte) = 0x00 and LSB (Least     Significant Byte) = 0x01
    // casting down to a single byte value LSB discarding higher bytes    

    return (*(char *) &Endian == 0x01) ? LITTLEENDIAN : BIGENDIAN;
} 

-2

मैं पाठ्यपुस्तक के माध्यम से जा रहा था: कंप्यूटर सिस्टम: एक प्रोग्रामर का परिप्रेक्ष्य , और यह निर्धारित करने के लिए एक समस्या है कि सी प्रोग्राम द्वारा कौन सा एंडियन है।

मैंने पॉइंटर की सुविधा का उपयोग निम्नानुसार किया:

#include <stdio.h>

int main(void){
    int i=1;
    unsigned char* ii = &i;

    printf("This computer is %s endian.\n", ((ii[0]==1) ? "little" : "big"));
    return 0;
}

जैसा कि int 4 बाइट्स लेता है, और char केवल 1 बाइट्स लेता है। हम एक इस्तेमाल कर सकते हैं चार सूचक को बात करने के लिए पूर्णांक मान 1 के साथ इस प्रकार अगर कंप्यूटर थोड़ा endian, है चार कि चार सूचक अंक के लिए मान 1 के साथ है, अन्यथा, अपने मूल्य 0 होना चाहिए।


यह int32t का उपयोग करके सुधार किया जाएगा।
शटल87

1
^ यदि आप नाइटपिक करना चाहते हैं, तो यहां सबसे अच्छा int16_fast_t है। और @ आर्किमिडीज़ 520 का वर्तमान कोड एक ऐसे आर्क पर काम नहीं करेगा जहाँ int natively int8 है;) (जो कि पहले सी मानकों के खिलाफ जा सकता है, हालाँकि)
hanshenrik
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.