सी में बड़े एंडियन को छोटे एंडियन में बदलें [बिना फंक का उपयोग किए] [बंद]


91

मुझे सी में छोटे एंडियन में बड़े एंडियन को बदलने के लिए एक फ़ंक्शन लिखने की आवश्यकता है। मैं किसी भी लाइब्रेरी फ़ंक्शन का उपयोग नहीं कर सकता हूं।


5
एक 16 बिट मूल्य? 32 बिट मूल्य? नाव? एक सरणी?
जॉन नॉवेलर

19
शायद एक जवाब चुनने का समय?
अनिकेत इनगे

7
फिर से मतदान करना। के रूप में ही stackoverflow.com/questions/105252/... सी ++ के लिए। हम केवल उस क्लीयर को बनाने के लिए संपादित कर सकते हैं।
सिरो सेंटिल्ली :52 冠状 iro i ''

जवाबों:


168

यह मानते हुए कि आपको एक साधारण बाइट स्वैप की आवश्यकता है, कुछ ऐसा प्रयास करें

निरस्त 16 बिट रूपांतरण:

swapped = (num>>8) | (num<<8);

निरुपित 32-बिट रूपांतरण:

swapped = ((num>>24)&0xff) | // move byte 3 to byte 0
                    ((num<<8)&0xff0000) | // move byte 1 to byte 2
                    ((num>>8)&0xff00) | // move byte 2 to byte 1
                    ((num<<24)&0xff000000); // byte 0 to byte 3

यह 1234 से 4321 तक के बाइट ऑर्डर को स्वैप करता है। यदि आपका इनपुट था 0xdeadbeef, तो 32-बिट एंडियन स्वैप का आउटपुट हो सकता है 0xefbeadde

ऊपर दिए गए कोड को मैक्रो या मैजिक नंबर के बजाय कम से कम स्थिरांक से साफ किया जाना चाहिए, लेकिन उम्मीद है कि यह मदद करता है

EDIT: जैसा कि एक अन्य उत्तर में बताया गया है, प्लेटफ़ॉर्म, OS और निर्देश सेट विशिष्ट विकल्प हैं जो उपरोक्त से अधिक तेज़ हो सकते हैं। लिनक्स कर्नेल में मैक्रोज़ (उदाहरण के लिए cpu_to_be32) हैं, जो एंडियननेस को बहुत अच्छी तरह से संभालते हैं। लेकिन ये विकल्प उनके वातावरण के लिए विशिष्ट हैं। व्यवहार में अंतःकरण उपलब्ध दृष्टिकोणों के मिश्रण का उपयोग करने के लिए सबसे अच्छा है


5
प्लेटफ़ॉर्म / हार्डवेयर-विशिष्ट विधियों का उल्लेख करने के लिए +1। प्रोग्राम हमेशा कुछ हार्डवेयर पर चलाए जाते हैं, और हार्डवेयर सुविधाएँ हमेशा सबसे तेज़ होती हैं।
eonil

21
अगर 16 बिट रूपांतरण के रूप में किया जाता है ((num & 0xff) >> 8) | (num << 8), तो gcc 4.8.3 एकल rolनिर्देश उत्पन्न करता है । और यदि 32 बिट रूपांतरण के रूप में लिखा गया है ((num & 0xff000000) >> 24) | ((num & 0x00ff0000) >> 8) | ((num & 0x0000ff00) << 8) | (num << 24), तो एक ही संकलक एक bswapनिर्देश उत्पन्न करता है ।
user666412

मैं नहीं जानता कि यह कितना कुशल है लेकिन Ive ने बाइट क्रम को इस तरह से बिटफ़ीड के साथ स्वैप किया: struct byte_t reverse(struct byte_t b) { struct byte_t rev; rev.ba = b.bh; rev.bb = b.bg; rev.bc = b.bf; rev.bd = b.be; rev.be = b.bd; rev.bf = b.bc; rev.bg = b.bb; rev.bh = b.ba; return rev;}जहां यह 8 फ़ील्ड 1 बिट प्रत्येक के साथ बिटफ़ील्ड है। लेकिन मुझे यकीन नहीं है कि अन्य सुझावों के रूप में उपवास करता है। Ints के union { int i; byte_t[sizeof(int)]; }लिए पूर्णांक में बाइट द्वारा रिवर्स बाइट को रिवर्स करने के लिए उपयोग करते हैं ।
इलियान जैप्रीआनोव

मुझे लगता है कि अभिव्यक्ति होनी चाहिए: (संख्या >> 8) | (संख्या << 8) बाइट ऑर्डर को उलटने के लिए और नहीं: ((संख्या & 0xff) >> 8) | (संख्या << 8), गलत उदाहरण कम बाइट में शून्य हो जाता है।
jscom

@IZZapryanov शायद +1 स्पष्टता के लिए है, लेकिन सी में बिटफ़िल्ड्स का उपयोग करना शायद ऐसा करने का सबसे कम कुशल तरीका है।
sherrellbc

104

शामिल करके:

#include <byteswap.h>

आप मशीन पर निर्भर बाइट-स्वैपिंग फ़ंक्शन का एक अनुकूलित संस्करण प्राप्त कर सकते हैं। फिर, आप आसानी से निम्नलिखित कार्यों का उपयोग कर सकते हैं:

__bswap_32 (uint32_t input)

या

__bswap_16 (uint16_t input)

3
आपके उत्तर के लिए धन्यवाद, लेकिन मैं
मार्क रैनसम

4
पढ़ना चाहिए #include <byteswap.h>, .h फ़ाइल में ही टिप्पणी देखें। इस पोस्ट में सहायक जानकारी है, इसलिए लेखक ने ओपी आवश्यकता को अनदेखा करने के बावजूद मतदान किया है, जो एक आवश्यक कार्य का उपयोग नहीं करता है।
एली रोसेंक्रूफ़

30
वास्तव में, __bswap_32 / __ bswap_16 फ़ंक्शंस वास्तव में मैक्रोज़ हैं न कि लाइब्रेरी फ़ंक्शंस, अप-वोट करने का एक और कारण।
एली रोसेंक्रूफ़

7
मेरी समझ यह है कि यह हेडर सभी आर्किटेक्चर पर सभी ऑपरेटिंग सिस्टम के लिए मौजूद होने की गारंटी नहीं है। मुझे अभी तक एंडियन मुद्दों से निपटने के लिए एक पोर्टेबल तरीका खोजना है।
एडवर्ड फॉक

2
विंडोज़ पर मौजूद नहीं है - कम से कम तब नहीं जब
लिंड

62
#include <stdint.h>


//! Byte swap unsigned short
uint16_t swap_uint16( uint16_t val ) 
{
    return (val << 8) | (val >> 8 );
}

//! Byte swap short
int16_t swap_int16( int16_t val ) 
{
    return (val << 8) | ((val >> 8) & 0xFF);
}

//! Byte swap unsigned int
uint32_t swap_uint32( uint32_t val )
{
    val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF ); 
    return (val << 16) | (val >> 16);
}

//! Byte swap int
int32_t swap_int32( int32_t val )
{
    val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF ); 
    return (val << 16) | ((val >> 16) & 0xFFFF);
}

अपडेट : 64 बिट बाइट स्वैपिंग जोड़ा गया

int64_t swap_int64( int64_t val )
{
    val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL );
    val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL );
    return (val << 32) | ((val >> 32) & 0xFFFFFFFFULL);
}

uint64_t swap_uint64( uint64_t val )
{
    val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL );
    val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL );
    return (val << 32) | (val >> 32);
}

के लिए int32_tऔर int64_tवेरिएंट, की मास्किंग के पीछे तर्क क्या है ... & 0xFFFFऔर ... & 0xFFFFFFFFULL? क्या साइन-एक्सटेंशन के साथ कुछ चल रहा है यहाँ मैं नहीं देख रहा हूँ? भी, क्यों swap_int64लौट रहा है uint64_t? ऐसा नहीं होना चाहिए int64_t?
14

1
स्वपन_६६६ एक यूइंट ६४ लौटाना वास्तव में एक त्रुटि है। हस्ताक्षरित अंतर मूल्यों के साथ मास्किंग वास्तव में संकेत को हटाने के लिए है। दाईं ओर शिफ्ट करना बाईं ओर साइन बिट को इंजेक्ट करता है। हम केवल अहस्ताक्षरित इंट स्वैपिंग ऑपरेशन को कॉल करके इससे बच सकते हैं।
chmike

धन्यवाद। आप swap_int64अपने उत्तर के लिए वापसी मूल्य के प्रकार को बदलना चाह सकते हैं । सहायक उत्तर के लिए +1, BTW!
bgoodr

क्या बिटवाइज़ और वैल्यू एंडियन पर निर्भर है?
माक्र्सज

1
LLमें अनावश्यक हैं (u)swap_uint64()ज्यादा एक तरह Lमें की जरूरत नहीं है (u)swap_uint32()। की Uजरूरत नहीं है uswap_uint64()जैसे बहुत Uजरूरी नहीं हैuswap_uint32()
chux - Reinstate Monica

13

यहाँ एक काफी सामान्य संस्करण है; मैंने इसे संकलित नहीं किया है, इसलिए शायद टाइपोस हैं, लेकिन आपको यह विचार करना चाहिए,

void SwapBytes(void *pv, size_t n)
{
    assert(n > 0);

    char *p = pv;
    size_t lo, hi;
    for(lo=0, hi=n-1; hi>lo; lo++, hi--)
    {
        char tmp=p[lo];
        p[lo] = p[hi];
        p[hi] = tmp;
    }
}
#define SWAP(x) SwapBytes(&x, sizeof(x));

NB: यहगति या स्थान के लिए अनुकूलित नहीं है। यह स्पष्ट (डीबग करने में आसान) और पोर्टेबल होने का इरादा है।

अपडेट 2018-04-04 ने n == 0 के अमान्य मामले को फंसाने के लिए ( @) जोड़ा, जैसा कि टिप्पणीकर्ता @chux द्वारा देखा गया है।


1
आप बेहतर प्रदर्शन के लिए xorSwap का उपयोग कर सकते हैं। इस जेनेरिक संस्करण को सभी आकार

मैंने इसका परीक्षण किया, यह पता चला है कि यह xorSwap ... x86 से अधिक तेज है। stackoverflow.com/questions/3128095/…

1
@nus - बहुत सरल कोड के फायदों में से एक यह है कि कंपाइलर ऑप्टिमाइज़र कभी-कभी इसे बहुत तेज़ बना सकता है।
माइकल जे

@MichaelJ OTOH, चामिक के उत्तर में ऊपर 32 बिट संस्करण bswapएक सक्षम निर्देश के अनुरूप संकलित X86 संकलक द्वारा एकल निर्देश पर संकलित हो जाता है । आकार के लिए एक पैरामीटर वाला यह संस्करण ऐसा नहीं कर सका।
अलनीतक

@Alnitak - जैसा कि मैंने कहा, मैंने कोई प्रयास नहीं किया tp अपने कोड को अनुकूलित करें। जब उपयोगकर्ता नेस पाया कि कोड बहुत तेजी से (एक मामले में) चला गया है तो मैंने सिर्फ सामान्य विचार का उल्लेख किया है कि सरल कोड को अक्सर एक कंपाइलर द्वारा अत्यधिक अनुकूलित किया जा सकता है। मेरा कोड विभिन्न प्रकार के मामलों के लिए काम करता है और इसे समझना बहुत आसान है और इस तरह डिबग करना आसान है। जो मेरे उद्देश्यों को पूरा करता है।
माइकल जे

8

यदि आपको मैक्रोज़ की जरूरत है (जैसे एम्बेडेड सिस्टम):

#define SWAP_UINT16(x) (((x) >> 8) | ((x) << 8))
#define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | ((x) << 24))

ये मैक्रो ठीक हैं, लेकिन (x ()) 24) विफल हो जाएगा जब एक हस्ताक्षरित पूर्णांक 0x80000000 और 0xffffffff के बीच होता है। यह एक अच्छा विचार है कि बिटवाइज़ और यहाँ का उपयोग करें। नोट: (x) << 24) पूरी तरह से सुरक्षित है। (x) >> 8) उच्चतर 16 बिट्स नॉनज़रो (या हस्ताक्षरित 16-बिट मान प्रदान किया गया हो) भी विफल हो जाएगा।

2
@ PacMan-- इन मैक्रो का उपयोग केवल अहस्ताक्षरित पूर्णांक स्वैप करने के लिए किया जाना है । इसलिए UINTउनके नाम में दम है।
kol

हाँ, सच है, शोर के लिए खेद है। यह एक टाइपकास्ट एम्बेड करने के लिए सबसे अच्छा नहीं होगा?

5

संपादित करें: ये पुस्तकालय के कार्य हैं। उनका अनुसरण करना मैनुअल तरीका है।

मैं __byteswap_ushort, __byteswap_ulong, और __byteswap_uint64 से अनजान लोगों की संख्या से बिल्कुल स्तब्ध हूं । सुनिश्चित करें कि वे विज़ुअल सी ++ विशिष्ट हैं, लेकिन वे x86 / IA-64 आर्किटेक्चर पर कुछ स्वादिष्ट कोड के लिए संकलित करते हैं। :)

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

uint32 cq_ntohl(uint32 a) {
    __asm{
        mov eax, a;
        bswap eax; 
    }
}

21
C प्रश्न के लिए, आप कुछ सुझाव दे रहे हैं जो Visual C ++ के लिए विशिष्ट है?
आलोक सिंघल

3
@ क्लोक: विजुअल C ++ माइक्रोसॉफ्ट का एक उत्पाद है। यह सी कोड संकलन के लिए ठीक काम करता है। :)
सैम हैरवेल

20
यह आपको अचेत क्यों करता है कि बहुत से लोग बाइटस्वापिंग के माइक्रोसॉफ्ट-विशिष्ट कार्यान्वयन के बारे में नहीं जानते हैं?
ड्रीमलैक्स

36
कूल, यह एक बंद स्रोत उत्पाद विकसित करने वाले किसी भी व्यक्ति के लिए अच्छी जानकारी है जिसे पोर्टेबल या मानकों के अनुरूप होने की आवश्यकता नहीं है।
सैम पोस्ट

6
@ आलोक, ओपी ने संकलक का उल्लेख नहीं किया | ओएस | किसी व्यक्ति को किसी विशेष उपकरण के साथ अपने अनुभव के अनुसार उत्तर देने की अनुमति है।
अनिकेत इनगे

5

हंसी में:


#include <stdio.h>

int main (int argc, char *argv[])
{
    size_t sizeofInt = sizeof (int);
    int i;

    union
    {
        int x;
        char c[sizeof (int)];
    } original, swapped;

    original.x = 0x12345678;

    for (i = 0; i < sizeofInt; i++)
        swapped.c[sizeofInt - i - 1] = original.c[i];

    fprintf (stderr, "%x\n", swapped.x);

    return 0;
}

7
हा हा हा हा हा। Hahaha। हा। हा? (क्या मजाक?)

3
क्या आपने इसे कुछ विंडोज सोर्स रिपॉजिटरी से खींचा है? :)
hochl

Nodejs इस तकनीक का उपयोग करता है! github.com/nodejs/node/blob/…
जस्टिन मोजर

उपयोग करने के लिए उत्सुक int i, size_t sizeofIntऔर दोनों के लिए एक ही प्रकार नहीं।
chux -

5

यहाँ एक तरीका है SSSE3 इंस्ट्रक्शन pshufb का उपयोग करके अपने इंटेल आंतरिक का उपयोग करते हुए, यह मानते हुए कि आपके पास 4 मिलियन से अधिक है int:

unsigned int *bswap(unsigned int *destination, unsigned int *source, int length) {
    int i;
    __m128i mask = _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3);
    for (i = 0; i < length; i += 4) {
        _mm_storeu_si128((__m128i *)&destination[i],
        _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)&source[i]), mask));
    }
    return destination;
}

3

क्या यह काम / तेज होगा?

 uint32_t swapped, result;

((byte*)&swapped)[0] = ((byte*)&result)[3];
((byte*)&swapped)[1] = ((byte*)&result)[2];
((byte*)&swapped)[2] = ((byte*)&result)[1];
((byte*)&swapped)[3] = ((byte*)&result)[0];

2
मुझे लगता है कि आपका मतलब है char, नहीं byte
ड्रीमलैक्स

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

1

यहां एक फ़ंक्शन है जिसका मैं उपयोग कर रहा हूं - किसी भी बुनियादी डेटा प्रकार पर परीक्षण और काम करता है:

//  SwapBytes.h
//
//  Function to perform in-place endian conversion of basic types
//
//  Usage:
//
//    double d;
//    SwapBytes(&d, sizeof(d));
//

inline void SwapBytes(void *source, int size)
{
    typedef unsigned char TwoBytes[2];
    typedef unsigned char FourBytes[4];
    typedef unsigned char EightBytes[8];

    unsigned char temp;

    if(size == 2)
    {
        TwoBytes *src = (TwoBytes *)source;
        temp = (*src)[0];
        (*src)[0] = (*src)[1];
        (*src)[1] = temp;

        return;
    }

    if(size == 4)
    {
        FourBytes *src = (FourBytes *)source;
        temp = (*src)[0];
        (*src)[0] = (*src)[3];
        (*src)[3] = temp;

        temp = (*src)[1];
        (*src)[1] = (*src)[2];
        (*src)[2] = temp;

        return;
    }

    if(size == 8)
    {
        EightBytes *src = (EightBytes *)source;
        temp = (*src)[0];
        (*src)[0] = (*src)[7];
        (*src)[7] = temp;

        temp = (*src)[1];
        (*src)[1] = (*src)[6];
        (*src)[6] = temp;

        temp = (*src)[2];
        (*src)[2] = (*src)[5];
        (*src)[5] = temp;

        temp = (*src)[3];
        (*src)[3] = (*src)[4];
        (*src)[4] = temp;

        return;
    }

}

2
कोड एक बहुत ही उचित धारणा पर निर्भर करता है: sourceआवश्यकतानुसार गठबंधन किया जाता है - फिर भी यदि वह धारणा धारण नहीं करता है, तो कोड यूबी है।
chux -

1

EDIT: यह फ़ंक्शन केवल 16 बिट शब्दों के संरेखित किए गए अंतरण को स्वैप करता है। एक फ़ंक्शन अक्सर UTF-16 / UCS-2 एन्कोडिंग के लिए आवश्यक होता है। संपादित करें END।

यदि आप एक मेमोरी ब्लॉक की समाप्ति को बदलना चाहते हैं तो आप मेरे धधकते हुए तेज़ दृष्टिकोण का उपयोग कर सकते हैं। आपकी मेमोरी सरणी का आकार 8 से अधिक होना चाहिए।

#include <stddef.h>
#include <limits.h>
#include <stdint.h>

void ChangeMemEndianness(uint64_t *mem, size_t size) 
{
uint64_t m1 = 0xFF00FF00FF00FF00ULL, m2 = m1 >> CHAR_BIT;

size = (size + (sizeof (uint64_t) - 1)) / sizeof (uint64_t);
for(; size; size--, mem++)
  *mem = ((*mem & m1) >> CHAR_BIT) | ((*mem & m2) << CHAR_BIT);
}

इस तरह का फ़ंक्शन यूनिकोड यूसीएस -2 / यूटीएफ -16 फाइलों की समाप्ति को बदलने के लिए उपयोगी है।


कोड पूरा करने के लिए CHAR_BIT #define गायब है।
तन्नु शमूएल

ठीक है, मैंने कहा कि लापता भी शामिल है।
पैट्रिक शाल्टर

यहाँ C ++ में एक स्वैप का लिंक है, मैं t know if itसुझाव के रूप में तेजी से डॉन है, लेकिन यह wokrs: github.com/heatblazer/helpers/blob/master/utils.h
Ilian Zapryanan

CHAR_BITइसके बजाय 8जिज्ञासु 0xFF00FF00FF00FF00ULLपर निर्भर है CHAR_BIT == 8। ध्यान दें कि LLनिरंतर में आवश्यक नहीं है।
chux -

आप ठीक कह रहे हैं केवल CHAR_BITउस मैक्रो के प्रदर्शन को बढ़ाने के लिए लिखा गया है। एलएल के लिए, यह किसी भी चीज़ की तुलना में अधिक एनोटेशन है। यह भी एक आदत है जिसे मैंने लंबे समय से छोटी गाड़ी संकलक (पूर्व मानक) के साथ पकड़ा था जो सही काम नहीं करेगा।
पैट्रिक श्ल्टर

1

यह कोड स्निपेट 32 बिट छोटे एंडियन नंबर को बिग एंडियन नंबर में बदल सकता है।

#include <stdio.h>
main(){    
    unsigned int i = 0xfafbfcfd;
    unsigned int j;    
    j= ((i&0xff000000)>>24)| ((i&0xff0000)>>8) | ((i&0xff00)<<8) | ((i&0xff)<<24);    
    printf("unsigned int j = %x\n ", j);    
}

धन्यवाद @YuHao मैं यहां नया हूं, पाठ को प्रारूपित करने का तरीका नहीं जानता।
कौशल बिलोर जूल

2
((i>>24)&0xff) | ((i>>8)&0xff00) | ((i&0xff00)<<8) | (i<<24);कुछ प्लेटफार्मों पर उपयोग तेज हो सकता है (उदाहरण के लिए एंड मास्क स्थिरांक को पुनर्चक्रण करना)। अधिकांश कंपाइलर ऐसा करेंगे, हालांकि, लेकिन कुछ सरल कंपाइलर आपके लिए इसे ऑप्टिमाइज़ नहीं कर सकते हैं।

-7

यदि आप x86 या x86_64 प्रोसेसर पर चल रहे हैं, तो बड़ा एंडियन देशी है। इसलिए

16 बिट मूल्यों के लिए

unsigned short wBigE = value;
unsigned short wLittleE = ((wBigE & 0xFF) << 8) | (wBigE >> 8);

32 बिट मूल्यों के लिए

unsigned int   iBigE = value;
unsigned int   iLittleE = ((iBigE & 0xFF) << 24)
                        | ((iBigE & 0xFF00) << 8)
                        | ((iBigE >> 8) & 0xFF00)
                        | (iBigE >> 24);

जब तक कंपाइलर यह बाइट स्तर में हेरफेर नहीं करता है और बाइट स्वैपिंग कोड उत्पन्न करता है, तब तक यह सबसे कुशल समाधान नहीं है। लेकिन यह किसी भी मेमोरी लेआउट ट्रिक पर निर्भर नहीं करता है और इसे आसानी से मैक्रो में बदल दिया जा सकता है।


25
X86 और x86_64 आर्किटेक्चर पर थोड़ा एंडियन स्कीम मूल निवासी है।
एमके उर्फ ​​ग्रिसू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.