मैं C ++ में बड़े-एंडियन और छोटे-एंडियन मूल्यों के बीच कैसे परिवर्तित करूं?


196

मैं C ++ में बड़े-एंडियन और छोटे-एंडियन मूल्यों के बीच कैसे परिवर्तित करूं?

संपादित करें: स्पष्टता के लिए, मुझे एक सीपीयू वास्तुकला से दूसरे में द्विआधारी डेटा (डबल-सटीक फ़्लोटिंग पॉइंट वैल्यू और 32-बिट और 64-बिट पूर्णांक) का अनुवाद करना होगा। इसमें नेटवर्किंग शामिल नहीं है, इसलिए ntoh () और इसी तरह के फ़ंक्शन यहां काम नहीं करेंगे।

EDIT # 2: मैंने जो उत्तर स्वीकार किया है वह सीधे उन कंपाइलरों पर लागू होता है जिन्हें मैं टारगेट कर रहा हूं (यही वजह है कि मैंने इसे चुना)। हालांकि, यहां अन्य बहुत अच्छे, अधिक पोर्टेबल उत्तर हैं।


21
ntoh hton ठीक काम करेगा, भले ही इसका नेटवर्किंग से कोई लेना-देना न हो।
बेन कॉलिन्स

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

10
hton ntoh काम नहीं करेगा यदि मशीन बड़ा-एंडियन है, क्योंकि प्रश्न पूछने वाला स्पष्ट रूप से रूपांतरण करना चाहता है।
फेबस्प्रो

6
@ jakobengblom2 इसका उल्लेख करने वाला एकमात्र व्यक्ति है। इस पृष्ठ के लगभग सभी उदाहरण अंतर्निहित अंतरण के अज्ञेय के बजाय "स्वैप" बाइट जैसी अवधारणाओं का उपयोग करते हैं। यदि आप बाहरी फ़ाइल स्वरूपों (जिसमें अच्छी तरह से परिभाषित धीरज को परिभाषित किया गया है) के साथ काम कर रहे हैं तो बाहरी डेटा को बाइट स्ट्रीम के रूप में माना जाता है, और मूल पूर्णांकों से बाइट स्ट्रीम को परिवर्तित करें। मैं short swap(short x)कोड को हर बार देखता हूं , क्योंकि अगर आप अलग-अलग धीरज के साथ एक मंच पर जाते हैं तो यह टूट जाएगा। मैथ्यू एम के पास केवल सही उत्तर है।
निशान लता

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

जवाबों:


166

यदि आप Visual C ++ का उपयोग कर रहे हैं, तो निम्न कार्य करें: आप intrin.h को शामिल करते हैं और निम्नलिखित कार्यों को कॉल करते हैं:

16 बिट संख्या के लिए:

unsigned short _byteswap_ushort(unsigned short value);

32 बिट संख्या के लिए:

unsigned long _byteswap_ulong(unsigned long value);

64 बिट संख्या के लिए:

unsigned __int64 _byteswap_uint64(unsigned __int64 value);

8 बिट संख्या (वर्ण) को परिवर्तित करने की आवश्यकता नहीं है।

इसके अलावा, वे केवल अहस्ताक्षरित मूल्यों के लिए परिभाषित होते हैं जो वे हस्ताक्षर किए गए पूर्णांक के लिए भी काम करते हैं।

फ्लोट्स और डबल्स के लिए यह प्लेन पूर्णांकों के साथ अधिक कठिन है क्योंकि ये मेजबान मशीनों बाइट-ऑर्डर में हो सकते हैं या नहीं। आप बड़े-एंडियन मशीनों पर छोटे-एंडियन फ्लोट्स प्राप्त कर सकते हैं और इसके विपरीत।

अन्य संकलक के समान आंतरिक भी हैं।

में जीसीसी उदाहरण के लिए आपसे सीधे बात कर के रूप में यहाँ प्रलेखित कुछ builtins :

uint32_t __builtin_bswap32 (uint32_t x)
uint64_t __builtin_bswap64 (uint64_t x)

(कुछ शामिल करने की आवश्यकता नहीं)। Afaik bit.h समान रूप से गैर-केंद्रित तरीके से समान फ़ंक्शन की घोषणा करता है।

16 बिट स्वैप यह सिर्फ एक बिट-रोटेट है।

अपने खुद के रोल करने के बजाय आंतरिक कॉलिंग आपको सबसे अच्छा प्रदर्शन और कोड घनत्व btw देता है ..


11
GCC के साथ, मैं उपयोग कर सकता हूं: #include <byteswap.h> int32_t bswap_32 (int32_t x) int64_t bswap_64 (int64_t x)
jmanning2th

5
__builtin_bswapXकेवल GCC-4.3 के बाद से उपलब्ध है
मैट जॉइनर

20
यह भी ध्यान देने योग्य बात यह है कि इन intrinsics / हमेशा / स्वैप बाइट्स, वे की तरह नहीं कर रहे हैं लायक है htonl, htonsआदि शामिल हो सकते अपनी स्थिति के संदर्भ से पता करने के लिए जब वास्तव में बाइट्स स्वैप करने के लिए है।
ब्रायन वैंडेनबर्ग

8
@ जेसन क्योंकि 8 बिट संख्या बड़े और छोटे एंडियन में समान हैं। :-)
Nils Pipenbrinck

2
@ ब्रायनवैंडबर्ग राइट; उपयोग करने के लिए htonlऔर ntohlसंदर्भ के बारे में चिंता किए बिना, पोर्टेबल कोड लिखते समय काम करेगा क्योंकि इन कार्यों को परिभाषित करने वाला प्लेटफ़ॉर्म इसे स्वैप करेगा यदि यह छोटा / मध्य-एंडियन है और बड़े-एंडियन पर यह एक नो-ऑप होगा। हालाँकि, जब एक मानक फ़ाइल प्रकार को डिकोडिंग किया जाता है, जिसे लिटिल-एंडियन (BMP कहते हैं) के रूप में परिभाषित किया जाता है, तब भी किसी को संदर्भ जानना होता है और वह केवल भरोसा नहीं कर सकता है htonlऔर ntohl
किंवदंतियों 2

86

सीधे शब्दों में कहें:

#include <climits>

template <typename T>
T swap_endian(T u)
{
    static_assert (CHAR_BIT == 8, "CHAR_BIT != 8");

    union
    {
        T u;
        unsigned char u8[sizeof(T)];
    } source, dest;

    source.u = u;

    for (size_t k = 0; k < sizeof(T); k++)
        dest.u8[k] = source.u8[sizeof(T) - k - 1];

    return dest.u;
}

उपयोग: swap_endian<uint32_t>(42)


3
एक उत्थान है। मैंने सिर्फ यूशर का उपयोग किया, और 4 से 1, 3 से 2, 2 से 3, और 1 से 4 को असाइन किया, लेकिन यदि आपके पास अलग-अलग आकार हैं तो यह अधिक लचीला है। 1 जनरल पेंटियम IIRC पर 6 घड़ियां। BSWAP 1 घड़ी है, लेकिन प्लेटफॉर्म विशिष्ट है।

2
@RocketRoy: हाँ, और अगर गति एक मुद्दा बन जाती है, तो प्लेटफॉर्म के साथ ओवरलोड लिखना बहुत आसान है- और टाइप-विशिष्ट इंट्रिक्टिक्स।
अलेक्जेंड्रे सी।

3
@MihaiTodor: चार्ट की एक सरणी के माध्यम से टाइपकास्टिंग के लिए यूनियनों के इस उपयोग को मानक द्वारा स्पष्ट रूप से अनुमति दी गई है। उदाहरण देखें। यह सवाल
एलेक्जेंडर सी।

4
@AlexandreC। C ++ मानक में नहीं - केवल C. C ++ में (जो यह कोड है) यह कोड अपरिभाषित व्यवहार है।
रप्त्ज

4
@Rapptz: 3.10 स्पष्ट प्रतीत होता है: "यदि कोई प्रोग्राम किसी वस्तु के संचित मूल्य तक पहुँचने का प्रयास करता है, तो निम्न प्रकार के व्यवहारों में से एक के माध्यम से किसी वस्तु का ग्लव्यू अपरिभाषित होता है: [...] एक चार या अहस्ताक्षरित चार प्रकार। " शायद मुझे यहाँ कुछ याद आ रहा है, लेकिन यह मेरे लिए बहुत स्पष्ट था कि चार बिंदुओं के माध्यम से किसी भी प्रकार तक पहुँचने की अनुमति स्पष्ट रूप से थी।
अलेक्जेंड्रे सी।

75

से बाइट आदेश भ्रम रोब पाईक द्वारा:

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

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

अगर यह बड़ा-सा है, तो इसे कैसे निकालें:

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

टीएल; डीआर: अपने प्लेटफ़ॉर्म देशी ऑर्डर के बारे में चिंता न करें, यह सब मायने रखता है जिस स्ट्रीम से आप पढ़ रहे हैं, उसकी बाइट ऑर्डर है, और आपको बेहतर उम्मीद है कि यह अच्छी तरह से परिभाषित है।

नोट: यह टिप्पणी में टिप्पणी की गई थी कि स्पष्ट प्रकार के रूपांतरण अनुपस्थित थे, यह महत्वपूर्ण था कि dataएक सरणी हो unsigned charया uint8_t। उपयोग signed charया char(यदि हस्ताक्षरित) के परिणामस्वरूप data[x]पूर्णांक में पदोन्नत किया जा सकता है और data[x] << 24संभावित रूप से 1 को साइन बिट में बदल दिया जाता है जो कि यूबी है।


6
यह अच्छा है, लेकिन यह मुझे लगता है कि यह केवल पूर्णांकों और वेरिएंट पर लागू होता है। फ्लोट्स / डबल्स का क्या करें?
ब्रेट

1
@ v.oddou: हां और नहीं, मेमोरी मैप की गई फाइलें नेटवर्क फ्रेम की तुलना में बिल्कुल समान हैं; यदि आप उन्हें सीधे नहीं पढना स्वीकार करते हैं, तो यह सब मायने रखता है कि उनका अंतःकरण है: यदि छोटा-एंडियन है, तो पहले सूत्र का उपयोग करें, यदि यह बड़ा-एंडियन है, तो दूसरे का उपयोग करें। इसके नमक के लायक कोई भी कंपाइलर अगर एंडियनस मैच करता है तो अनावश्यक रूप से रूपांतरणों का अनुकूलन करेगा।
Matthieu M.

2
@meowsqueak: हाँ, मुझे उम्मीद है कि यह काम करेगा, क्योंकि केवल बाइट्स का क्रम बदलता है, प्रत्येक बाइट के भीतर बिट्स का क्रम नहीं।
Matthieu M.

3
शिथिल रूप से संबंधित नोट पर, लिंक की गई पोस्ट कुछ अप्रिय पढ़ी गई है ... आदमी को संक्षिप्तता का मूल्य लगता है, फिर भी वह उन सभी बुरे प्रोग्रामर के बारे में एक लंबा रेंट लिखना पसंद करता है जो उतने ही प्रबुद्ध नहीं हैं जितना कि वह वास्तव में, इसके बजाय वास्तव में स्थिति की व्याख्या करना और उसका समाधान हमेशा काम करता है।
विज्ञापन एन

1
यदि आप इस पद्धति का उपयोग कर रहे हैं, तो सुनिश्चित करें कि आपने अपना डेटा (अहस्ताक्षरित चार *)
joseph

51

यदि आप नेटवर्क / होस्ट की अनुकूलता के प्रयोजनों के लिए ऐसा कर रहे हैं, तो आपको इसका उपयोग करना चाहिए:

ntohl() //Network to Host byte order (Long)
htonl() //Host to Network byte order (Long)

ntohs() //Network to Host byte order (Short)
htons() //Host to Network byte order (Short)

यदि आप किसी अन्य कारण के लिए ऐसा कर रहे हैं तो यहां प्रस्तुत बाइट_स्वाप समाधान में से एक ठीक काम करेगा।


2
नेटवर्क बाइट ऑर्डर बड़ा एंडियन है मेरा मानना ​​है। यदि आप नेटवर्क कोड का उपयोग नहीं कर रहे हैं, तब भी इन कार्यों को ध्यान में रखकर उपयोग किया जा सकता है। हालाँकि कोई भी फ्लोट संस्करण नहीं है ntohf या htonf
मैट

2
मैट एच। जो कि ज्यादातर सही है। सभी कंप्यूटर सिस्टम में छोटे-एंडियन बाइट ऑर्डर नहीं होते हैं। यदि आप काम कर रहे थे, तो एक मोटरोला 68k, एक पावरपीसी या एक अन्य बड़े-एंडियन आर्किटेक्चर का कहना है कि ये फ़ंक्शन बाइट्स को स्वैप नहीं करेंगे, क्योंकि वे पहले से ही 'नेटवर्क बाइट ऑर्डर में हैं।
फ्रॉस्टी

2
दुर्भाग्य से, htonlऔर ntohlबड़े एंडियन प्लेटफ़ॉर्म पर छोटे एंडियन के लिए नहीं जा सकते।
ब्रायन वंडेनबर्ग

2
@celtschk, समझा; हालांकि, ओपी एक बड़े-एंडियन वातावरण में भी, धीरज रखने का एक तरीका चाहता है।
ब्रायन वंडेनबर्ग

4
अपरिहार्य प्रश्न को दूर करने के लिए: बीई मंच के लिए एलई की आवश्यकता के कई कारण हैं; फ़ाइल स्वरूपों की एक संख्या (bmp, fli, pcx, qtm, rtf, tga कुछ नाम करने के लिए) थोड़ा एंडियन मूल्यों का उपयोग करें ... या कम से कम, प्रारूप के कुछ संस्करण वैसे भी एक समय में किया था।
ब्रायन वंडेनबर्ग

26

मैंने इस पोस्ट से कुछ सुझाव लिए और उन्हें एक साथ रखने के लिए इसे तैयार किया:

#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
#include <boost/detail/endian.hpp>
#include <stdexcept>

enum endianness
{
    little_endian,
    big_endian,
    network_endian = big_endian,

    #if defined(BOOST_LITTLE_ENDIAN)
        host_endian = little_endian
    #elif defined(BOOST_BIG_ENDIAN)
        host_endian = big_endian
    #else
        #error "unable to determine system endianness"
    #endif
};

namespace detail {

template<typename T, size_t sz>
struct swap_bytes
{
    inline T operator()(T val)
    {
        throw std::out_of_range("data size");
    }
};

template<typename T>
struct swap_bytes<T, 1>
{
    inline T operator()(T val)
    {
        return val;
    }
};

template<typename T>
struct swap_bytes<T, 2>
{
    inline T operator()(T val)
    {
        return ((((val) >> 8) & 0xff) | (((val) & 0xff) << 8));
    }
};

template<typename T>
struct swap_bytes<T, 4>
{
    inline T operator()(T val)
    {
        return ((((val) & 0xff000000) >> 24) |
                (((val) & 0x00ff0000) >>  8) |
                (((val) & 0x0000ff00) <<  8) |
                (((val) & 0x000000ff) << 24));
    }
};

template<>
struct swap_bytes<float, 4>
{
    inline float operator()(float val)
    {
        uint32_t mem =swap_bytes<uint32_t, sizeof(uint32_t)>()(*(uint32_t*)&val);
        return *(float*)&mem;
    }
};

template<typename T>
struct swap_bytes<T, 8>
{
    inline T operator()(T val)
    {
        return ((((val) & 0xff00000000000000ull) >> 56) |
                (((val) & 0x00ff000000000000ull) >> 40) |
                (((val) & 0x0000ff0000000000ull) >> 24) |
                (((val) & 0x000000ff00000000ull) >> 8 ) |
                (((val) & 0x00000000ff000000ull) << 8 ) |
                (((val) & 0x0000000000ff0000ull) << 24) |
                (((val) & 0x000000000000ff00ull) << 40) |
                (((val) & 0x00000000000000ffull) << 56));
    }
};

template<>
struct swap_bytes<double, 8>
{
    inline double operator()(double val)
    {
        uint64_t mem =swap_bytes<uint64_t, sizeof(uint64_t)>()(*(uint64_t*)&val);
        return *(double*)&mem;
    }
};

template<endianness from, endianness to, class T>
struct do_byte_swap
{
    inline T operator()(T value)
    {
        return swap_bytes<T, sizeof(T)>()(value);
    }
};
// specialisations when attempting to swap to the same endianess
template<class T> struct do_byte_swap<little_endian, little_endian, T> { inline T operator()(T value) { return value; } };
template<class T> struct do_byte_swap<big_endian,    big_endian,    T> { inline T operator()(T value) { return value; } };

} // namespace detail

template<endianness from, endianness to, class T>
inline T byte_swap(T value)
{
    // ensure the data is only 1, 2, 4 or 8 bytes
    BOOST_STATIC_ASSERT(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8);
    // ensure we're only swapping arithmetic types
    BOOST_STATIC_ASSERT(boost::is_arithmetic<T>::value);

    return detail::do_byte_swap<from, to, T>()(value);
}

आपको <cstdint> या <stdint.h> को भी शामिल करना होगा, उदाहरण के लिए, uint32_t के लिए
ady

17

बड़े-एंडियन से छोटे-एंडियन तक जाने की प्रक्रिया उसी तरह है जैसे कि छोटे-एंडियन से बड़े-एंडियन तक जाने की प्रक्रिया।

यहाँ कुछ उदाहरण कोड है:

void swapByteOrder(unsigned short& us)
{
    us = (us >> 8) |
         (us << 8);
}

void swapByteOrder(unsigned int& ui)
{
    ui = (ui >> 24) |
         ((ui<<8) & 0x00FF0000) |
         ((ui>>8) & 0x0000FF00) |
         (ui << 24);
}

void swapByteOrder(unsigned long long& ull)
{
    ull = (ull >> 56) |
          ((ull<<40) & 0x00FF000000000000) |
          ((ull<<24) & 0x0000FF0000000000) |
          ((ull<<8) & 0x000000FF00000000) |
          ((ull>>8) & 0x00000000FF000000) |
          ((ull>>24) & 0x0000000000FF0000) |
          ((ull>>40) & 0x000000000000FF00) |
          (ull << 56);
}

2
यहां पोस्ट किया गया अंतिम फ़ंक्शन गलत है, और इसे संपादित किया जाना चाहिए: void swapByteOrder (अहस्ताक्षरित लंबे समय और ull) {ull = (ull >> 56) | ... (ull << 56); }
एरिक बर्नेट

14
मुझे नहीं लगता कि बिटवाइज़-एंड (() के विपरीत तार्किक-और (&&) का उपयोग करना सही है। सी ++ की युक्ति के अनुसार, दोनों ऑपरेंड को स्पष्ट रूप से बूल में बदल दिया जाता है, जो कि आप नहीं चाहते हैं।
ट्रेवर रॉबिन्सन

16

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

विजुअल स्टूडियो, या अधिक सटीक रूप से विजुअल C ++ रनटाइम लाइब्रेरी, को इसके लिए प्लेटफ़ॉर्म इंट्रिंसिक्स कहा जाता है _byteswap_ushort(), _byteswap_ulong(), and _byteswap_int64()। अन्य प्लेटफार्मों के लिए भी ऐसा ही होना चाहिए, लेकिन मुझे नहीं पता कि उन्हें क्या कहा जाएगा।


यह एक बड़ी कड़ी है। यह x86 असेंबलर में मेरी रुचि को फिर से जागृत कर रहा है।
पीपी।

1
बीएसडब्ल्यूएपी के लिए समय के परिणाम यहां प्रस्तुत किए गए हैं। gmplib.org/~tege/x86-timing.pdf ... और यहाँ ... agner.org/optimize/instruction_tables.pdf

12

हमने इसे टेम्प्लेट के साथ किया है। आप ऐसा कुछ कर सकते हैं:

// Specialization for 2-byte types.
template<>
inline void endian_byte_swapper< 2 >(char* dest, char const* src)
{
    // Use bit manipulations instead of accessing individual bytes from memory, much faster.
    ushort* p_dest = reinterpret_cast< ushort* >(dest);
    ushort const* const p_src = reinterpret_cast< ushort const* >(src);
    *p_dest = (*p_src >> 8) | (*p_src << 8);
}

// Specialization for 4-byte types.
template<>
inline void endian_byte_swapper< 4 >(char* dest, char const* src)
{
    // Use bit manipulations instead of accessing individual bytes from memory, much faster.
    uint* p_dest = reinterpret_cast< uint* >(dest);
    uint const* const p_src = reinterpret_cast< uint const* >(src);
    *p_dest = (*p_src >> 24) | ((*p_src & 0x00ff0000) >> 8) | ((*p_src & 0x0000ff00) << 8) | (*p_src << 24);
}

8

यदि आप ऐसा कर रहे हैं तो विभिन्न प्लेटफार्मों के बीच डेटा को स्थानांतरित करने के लिए ntoh और hton फ़ंक्शन देखें।


7

उसी तरह से आप सी में करते हैं:

short big = 0xdead;
short little = (((big & 0xff)<<8) | ((big & 0xff00)>>8));

आप भी बिना किसी वर्ण के वेक्टर की घोषणा कर सकते हैं, उसमें इनपुट मान को कम कर सकते हैं, बाइट्स को दूसरे वेक्टर में बदल सकते हैं और बाइट्स को बाहर निकाल सकते हैं, लेकिन यह बिट-ट्विडलिंग की तुलना में लंबे समय तक परिमाण का आदेश लेगा, विशेष रूप से 64-बिट मानों से।


7

अधिकांश POSIX सिस्टम पर (इसके द्वारा POSIX मानक में नहीं है) endian.h है, जिसका उपयोग यह निर्धारित करने के लिए किया जा सकता है कि आपका सिस्टम किस एन्कोडिंग का उपयोग करता है। वहाँ से यह कुछ इस तरह है:

unsigned int change_endian(unsigned int x)
{
    unsigned char *ptr = (unsigned char *)&x;
    return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
}

यह ऑर्डर स्वैप करता है (बड़े एंडियन से लेकर छोटे एंडियन तक):

यदि आपके पास 0xDEADBEEF (थोड़े एंडियन सिस्टम पर 0xEFBEADDE के रूप में संग्रहीत) संख्या है, तो ptr [0] 0xEF, ptr [1] 0xBE, आदि होगा।

लेकिन अगर आप इसे नेटवर्किंग के लिए उपयोग करना चाहते हैं, तो htons, htonl और htonll (और उनके व्युत्क्रम ntohs, ntohl और ntohll) होस्ट ऑर्डर से नेटवर्क ऑर्डर में परिवर्तित करने के लिए सहायक होंगे।


6
यह मज़ेदार है - opengroup.org/onlinepubs/9699919799/toc.htm पर POSIX मानक एक हेडर '<endian.h>' का उल्लेख नहीं करता है।
जोनाथन लेफ़लर

1
आप उपयोग कर सकते हैं htonlऔर दोस्तों की परवाह किए बिना उपयोग-मामले का नेटवर्किंग से कोई लेना-देना नहीं है। नेटवर्क बाइट ऑर्डर बड़ा-एंडियन है, इसलिए उन कार्यों को host_to_be और be_to_host के रूप में समझें। (यदि आपको host_to_le, यद्यपि की आवश्यकता नहीं है, तो मदद नहीं करता है।)
पीटर

5

ध्यान दें कि, विंडोज के लिए कम से कम, htonl () उनके आंतरिक समकक्ष _byteswap_ulong () की तुलना में बहुत धीमा है। पूर्व में DLL लाइब्रेरी कॉल ws2_32.dll है, बाद वाला एक BSWAP विधानसभा निर्देश है। इसलिए, यदि आप कुछ प्लेटफ़ॉर्म-निर्भर कोड लिख रहे हैं, तो गति के लिए आंतरिक का उपयोग करना पसंद करें:

#define htonl(x) _byteswap_ulong(x)

यह .PNG इमेज प्रोसेसिंग के लिए विशेष रूप से महत्वपूर्ण हो सकता है, जहां सभी पूर्णांकों को बिग एंडियन में स्पष्टीकरण के साथ सहेजा जाता है "यदि आप तैयार नहीं हैं, तो ठेठ विंडोज प्रोग्राम को धीमा करने के लिए {htonl () ..." {का उपयोग कर सकते हैं}।


4

अधिकांश प्लेटफार्मों में एक सिस्टम हेडर फ़ाइल होती है जो कुशल बाइट्सवाप फ़ंक्शन प्रदान करती है। लिनक्स में यह अंदर है <endian.h>। आप इसे C ++ में अच्छी तरह से लपेट सकते हैं:

#include <iostream>

#include <endian.h>

template<size_t N> struct SizeT {};

#define BYTESWAPS(bits) \
template<class T> inline T htobe(T t, SizeT<bits / 8>) { return htobe ## bits(t); } \
template<class T> inline T htole(T t, SizeT<bits / 8>) { return htole ## bits(t); } \
template<class T> inline T betoh(T t, SizeT<bits / 8>) { return be ## bits ## toh(t); } \
template<class T> inline T letoh(T t, SizeT<bits / 8>) { return le ## bits ## toh(t); }

BYTESWAPS(16)
BYTESWAPS(32)
BYTESWAPS(64)

#undef BYTESWAPS

template<class T> inline T htobe(T t) { return htobe(t, SizeT<sizeof t>()); }
template<class T> inline T htole(T t) { return htole(t, SizeT<sizeof t>()); }
template<class T> inline T betoh(T t) { return betoh(t, SizeT<sizeof t>()); }
template<class T> inline T letoh(T t) { return letoh(t, SizeT<sizeof t>()); }

int main()
{
    std::cout << std::hex;
    std::cout << htobe(static_cast<unsigned short>(0xfeca)) << '\n';
    std::cout << htobe(0xafbeadde) << '\n';

    // Use ULL suffix to specify integer constant as unsigned long long 
    std::cout << htobe(0xfecaefbeafdeedfeULL) << '\n';
}

आउटपुट:

cafe
deadbeaf
feeddeafbeefcafe

बदलें: #define BYTESWAPS (बिट्स) \ टेम्पलेट <क्लास टी> इनलाइन टी htobe (टी टी, साइज टी <बिट्स / 8>) {वापसी htobe ## बिट्स (टी); } \ टेम्पलेट <वर्ग टी> इनलाइन टी htole (टी टी, SizeT <बिट्स / 8>) {वापसी htole ## बिट्स (टी); } \ टेम्पलेट <वर्ग टी> इनलाइन टी बेटोह (टी टी, साइजटीटी <बिट्स / 8>) {वापसी हो ## बिट्स ## तोह (टी); } \ टेम्पलेट <वर्ग टी> इनलाइन टी लेटोह (टी टी, साइजटीटी <बिट्स / 8>) {रिटर्न ले ## बिट्स ## टॉ (टी); }
ldav1s

धन्यवाद, betoh () और letoh () का परीक्षण करना भूल गए।
मैक्सिम Egorushkin

4

मुझे यह पसंद है, बस स्टाइल के लिए :-)

long swap(long i) {
    char *c = (char *) &i;
    return * (long *) (char[]) {c[3], c[2], c[1], c[0] };
}

मुझे char[]'त्रुटि: अधूरा प्रकार की अनुमति नहीं है' कहने पर एक त्रुटि मिलती है
पोर्टलैंड रनर

4

गंभीरता से ... मुझे समझ नहीं आता कि सभी समाधान इतने जटिल क्यों हैं ! कैसे के बारे में सबसे सरल, सबसे सामान्य टेम्पलेट फ़ंक्शन जो किसी भी ऑपरेटिंग सिस्टम में किसी भी परिस्थिति में किसी भी आकार के किसी भी प्रकार को स्वैप करता है ????

template <typename T>
void SwapEnd(T& var)
{
    static_assert(std::is_pod<T>::value, "Type must be POD type for safety");
    std::array<char, sizeof(T)> varArray;
    std::memcpy(varArray.data(), &var, sizeof(T));
    for(int i = 0; i < static_cast<int>(sizeof(var)/2); i++)
        std::swap(varArray[sizeof(var) - 1 - i],varArray[i]);
    std::memcpy(&var, varArray.data(), sizeof(T));
}

यह एक साथ C और C ++ की जादुई शक्ति है! बस चरित्र द्वारा मूल चर चरित्र स्वैप।

बिंदु 1 : कोई ऑपरेटर नहीं: याद रखें कि मैंने साधारण असाइनमेंट ऑपरेटर "=" का उपयोग नहीं किया था क्योंकि एंडियननेस फ़्लिप होने पर कुछ ऑब्जेक्ट गड़बड़ हो जाएंगे और कॉपी कंस्ट्रक्टर (या असाइनमेंट ऑपरेटर) काम नहीं करेगा। इसलिए, उन्हें चार्ट द्वारा चार्ट की नकल करना अधिक विश्वसनीय है।

बिंदु 2 : संरेखण मुद्दों से अवगत रहें: ध्यान दें कि हम एक सरणी से और उसके पास कॉपी कर रहे हैं, जो कि सही बात है क्योंकि C ++ कंपाइलर गारंटी नहीं देता है कि हम अनलॉग्ड मेमोरी तक पहुँच सकते हैं (यह उत्तर इसके मूल से अपडेट किया गया था इसके लिए फार्म)। उदाहरण के लिए, यदि आप आवंटित करते हैं uint64_t, तो आपका कंपाइलर गारंटी नहीं दे सकता है कि आप उस के रूप में 3 के बाइट का उपयोग कर सकते हैं uint8_t। इसलिए, सही बात यह है कि इसे चार सरणी में कॉपी करें, इसे स्वैप करें, फिर इसे वापस कॉपी करें (इसलिए नहीं reinterpret_cast)। ध्यान दें कि संकलक ज्यादातर स्मार्ट होते हैं जो कि आपने क्या किया reinterpret_castअगर वे संरेखण की परवाह किए बिना व्यक्तिगत बाइट्स तक पहुंचने में सक्षम हैं, तो इसे वापस करने के लिए ।

इस फ़ंक्शन का उपयोग करने के लिए :

double x = 5;
SwapEnd(x);

और अब xअंतस में अलग है।


2
यह कहीं भी काम करेगा, लेकिन निर्मित असेंबली ऑकडे अक्सर उप
रूपी

आप का उपयोग new/ deleteइस के लिए एक बफर आवंटित करने के लिए?!? sizeof(var)एक संकलन-समय स्थिर है, इसलिए आप कर सकते हैं char varSwapped[sizeof(var)]। या आप कर सकते हैं char *p = reinterpret_cast<char*>(&var)और जगह में स्वैप कर सकते हैं ।
पीटर कॉर्डेस

@ यह उत्तर एक बिंदु को साबित करने के लिए त्वरित और गंदा है। मैं आपके सुझावों पर अमल करूंगा। हालाँकि, आपको दिए गए 50-लाइन समाधानों की तुलना में मेगा SO AH और 5-लाइन समाधान का डाउन-वोट नहीं होना चाहिए। मैं और कहने वाला नहीं हूँ।
क्वांटम भौतिक विज्ञानी

यह उत्तर गलत एंड-एंडियन डेटा पर कंस्ट्रक्टरों और अतिभारित ऑपरेटरों के साथ सावधानी बरतने के बारे में कुछ उपयोगी बिंदु बनाता है, इसलिए कोड के भयानक नहीं होने पर मुझे अपने डाउनवोट को हटाने में खुशी होगी, और यह एक अच्छा कंपाइलर एक bswap में संकलित कर सकता है अनुदेश। इसके अलावा, मैं for(size_t i = 0 ; i < sizeof(var) ; i++)एक के बजाय का उपयोग करना चाहते हैं static_cast<long>। (या वास्तव में, इन-प्लेस स्वैप एक आरोही और अवरोही का उपयोग करेगा char*ताकि किसी भी तरह से चला जाए)।
पीटर कॉर्ड्स

जैसे देखें मार्क Ransom का जवाब std का उपयोग करें :: स्वैप करने के लिए जगह में उल्टा।
पीटर कॉर्डेस

3

मेरे पास यह कोड है जो मुझे HOST_ENDIAN_ORDER (जो भी हो) से LITTLE_ENDIAN_ORDER या BIG_ENDIAN_ORDER में कनवर्ट करने की अनुमति देता है। मैं एक टेम्पलेट का उपयोग करता हूं, इसलिए यदि मैं HOST_ENDIAN_ORDER से LITTLE_ENDIAN_ORDER में कनवर्ट करने का प्रयास करता हूं और वे मशीन के लिए समान होते हैं जो मैं संकलित करता हूं, तो कोई कोड उत्पन्न नहीं होगा।

यहाँ कुछ टिप्पणियों के साथ कोड है:

// We define some constant for little, big and host endianess. Here I use 
// BOOST_LITTLE_ENDIAN/BOOST_BIG_ENDIAN to check the host indianess. If you
// don't want to use boost you will have to modify this part a bit.
enum EEndian
{
  LITTLE_ENDIAN_ORDER,
  BIG_ENDIAN_ORDER,
#if defined(BOOST_LITTLE_ENDIAN)
  HOST_ENDIAN_ORDER = LITTLE_ENDIAN_ORDER
#elif defined(BOOST_BIG_ENDIAN)
  HOST_ENDIAN_ORDER = BIG_ENDIAN_ORDER
#else
#error "Impossible de determiner l'indianness du systeme cible."
#endif
};

// this function swap the bytes of values given it's size as a template
// parameter (could sizeof be used?).
template <class T, unsigned int size>
inline T SwapBytes(T value)
{
  union
  {
     T value;
     char bytes[size];
  } in, out;

  in.value = value;

  for (unsigned int i = 0; i < size / 2; ++i)
  {
     out.bytes[i] = in.bytes[size - 1 - i];
     out.bytes[size - 1 - i] = in.bytes[i];
  }

  return out.value;
}

// Here is the function you will use. Again there is two compile-time assertion
// that use the boost librarie. You could probably comment them out, but if you
// do be cautious not to use this function for anything else than integers
// types. This function need to be calles like this :
//
//     int x = someValue;
//     int i = EndianSwapBytes<HOST_ENDIAN_ORDER, BIG_ENDIAN_ORDER>(x);
//
template<EEndian from, EEndian to, class T>
inline T EndianSwapBytes(T value)
{
  // A : La donnée à swapper à une taille de 2, 4 ou 8 octets
  BOOST_STATIC_ASSERT(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8);

  // A : La donnée à swapper est d'un type arithmetic
  BOOST_STATIC_ASSERT(boost::is_arithmetic<T>::value);

  // Si from et to sont du même type on ne swap pas.
  if (from == to)
     return value;

  return SwapBytes<T, sizeof(T)>(value);
}

3

यदि एक बड़ा-एंडियन 32-बिट अहस्ताक्षरित पूर्णांक 0xAABBCCDD जैसा दिखता है, जो 2864434397 के बराबर है, तो वही 32-बिट अहस्ताक्षरित पूर्णांक-अंत प्रोसेसर पर 0xDDCCBBAA जैसा दिखता है, जो 2864434397 के बराबर भी है।

यदि एक बड़ा-एंडियन 16-बिट अहस्ताक्षरित 0xAABB जैसा दिखता है, जो 43707 के बराबर है, तो वही 16-बिट अहस्ताक्षरित छोटा-एंडियन प्रोसेसर पर 0xBBAA जैसा दिखता है, जो 43007 के बराबर भी है।

यहाँ छोटे से एंडियन से बड़े-एंडियन और इसके विपरीत - बाइट्स को स्वैप करने के लिए काम के कुछ जोड़े हैं

// can be used for short, unsigned short, word, unsigned word (2-byte types)
#define BYTESWAP16(n) (((n&0xFF00)>>8)|((n&0x00FF)<<8))

// can be used for int or unsigned int or float (4-byte types)
#define BYTESWAP32(n) ((BYTESWAP16((n&0xFFFF0000)>>16))|((BYTESWAP16(n&0x0000FFFF))<<16))

// can be used for unsigned long long or double (8-byte types)
#define BYTESWAP64(n) ((BYTESWAP32((n&0xFFFFFFFF00000000)>>32))|((BYTESWAP32(n&0x00000000FFFFFFFF))<<32))

2

यहाँ एक सामान्यीकृत संस्करण है जो मेरे सिर के ऊपर से निकला है, जिसके स्थान पर एक मूल्य स्वैप है। यदि प्रदर्शन एक समस्या है तो अन्य सुझाव बेहतर होंगे।

 template<typename T>
    void ByteSwap(T * p)
    {
        for (int i = 0;  i < sizeof(T)/2;  ++i)
            std::swap(((char *)p)[i], ((char *)p)[sizeof(T)-1-i]);
    }

अस्वीकरण: मैंने इसे संकलित करने या अभी तक परीक्षण करने की कोशिश नहीं की है।


2

यदि आप एक शब्द में बिट्स के क्रम को उलटने के लिए सामान्य पैटर्न लेते हैं, और प्रत्येक बाइट के भीतर बिट्स को उलट देने वाले भाग को रोकते हैं, तो आपको कुछ चीज़ों के साथ छोड़ दिया जाता है जो केवल एक शब्द के भीतर बाइट्स को उलट देता है। 64-बिट्स के लिए:

x = ((x & 0x00000000ffffffff) << 32) ^ ((x >> 32) & 0x00000000ffffffff);
x = ((x & 0x0000ffff0000ffff) << 16) ^ ((x >> 16) & 0x0000ffff0000ffff);
x = ((x & 0x00ff00ff00ff00ff) <<  8) ^ ((x >>  8) & 0x00ff00ff00ff00ff);

कंपाइलर को सुपरफ्लस बिट-मास्किंग ऑपरेशन को साफ करना चाहिए (मैंने पैटर्न को उजागर करने के लिए उन्हें छोड़ दिया), लेकिन अगर ऐसा नहीं होता है तो आप इस तरह से पहली पंक्ति को फिर से लिख सकते हैं:

x = ( x                       << 32) ^  (x >> 32);

यह सामान्य रूप से अधिकांश आर्किटेक्चर पर एक ही बारी बारी से निर्देश को सरल करना चाहिए (यह देखते हुए कि पूरा ऑपरेशन शायद एक निर्देश है)।

RISC प्रोसेसर पर, बड़े, जटिल स्थिरांक संकलक कठिनाइयों का कारण बन सकते हैं। आप पिछले एक से लगातार प्रत्येक की गणना कर सकते हैं, हालांकि। इस तरह:

uint64_t k = 0x00000000ffffffff; /* compiler should know a trick for this */
x = ((x & k) << 32) ^ ((x >> 32) & k);
k ^= k << 16;
x = ((x & k) << 16) ^ ((x >> 16) & k);
k ^= k << 8;
x = ((x & k) <<  8) ^ ((x >>  8) & k);

यदि आप चाहें, तो आप इसे एक लूप के रूप में लिख सकते हैं। यह कुशल नहीं होगा, लेकिन सिर्फ मनोरंजन के लिए:

int i = sizeof(x) * CHAR_BIT / 2;
uintmax_t k = (1 << i) - 1;
while (i >= 8)
{
    x = ((x & k) << i) ^ ((x >> i) & k);
    i >>= 1;
    k ^= k << i;
}

और पूर्णता के लिए, यहां पहले फॉर्म का सरलीकृत 32-बिट संस्करण है:

x = ( x               << 16) ^  (x >> 16);
x = ((x & 0x00ff00ff) <<  8) ^ ((x >>  8) & 0x00ff00ff);

2

बस मैंने सोचा कि मैंने अपना समाधान यहाँ जोड़ा क्योंकि मैंने इसे कहीं नहीं देखा है। यह एक छोटा और पोर्टेबल C ++ टेम्पर्ड फ़ंक्शन और पोर्टेबल है जो केवल बिट ऑपरेशंस का उपयोग करता है।

template<typename T> inline static T swapByteOrder(const T& val) {
    int totalBytes = sizeof(val);
    T swapped = (T) 0;
    for (int i = 0; i < totalBytes; ++i) {
        swapped |= (val >> (8*(totalBytes-i-1)) & 0xFF) << (8*i);
    }
    return swapped;
}

2

मैं वास्तव में आश्चर्यचकित हूं कि किसी ने htobeXX और betohXX फ़ंक्शन का उल्लेख नहीं किया है। वे एंडियन.एच में परिभाषित हैं और नेटवर्क कार्यों htonXX के समान हैं।


2

नीचे दिए गए कोड का उपयोग करके, आप BigEndian और LittleEndian के बीच आसानी से स्वैप कर सकते हैं

#define uint32_t unsigned 
#define uint16_t unsigned short

#define swap16(x) ((((uint16_t)(x) & 0x00ff)<<8)| \
(((uint16_t)(x) & 0xff00)>>8))

#define swap32(x) ((((uint32_t)(x) & 0x000000ff)<<24)| \
(((uint32_t)(x) & 0x0000ff00)<<8)| \
(((uint32_t)(x) & 0x00ff0000)>>8)| \
(((uint32_t)(x) & 0xff000000)>>24))

1

मैंने हाल ही में C में ऐसा करने के लिए एक मैक्रो लिखा है, लेकिन यह C ++ में समान रूप से मान्य है:

#define REVERSE_BYTES(...) do for(size_t REVERSE_BYTES=0; REVERSE_BYTES<sizeof(__VA_ARGS__)>>1; ++REVERSE_BYTES)\
    ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES],\
    ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES],\
    ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES];\
while(0)

यह किसी भी प्रकार को स्वीकार करता है और पारित तर्क में बाइट्स को उलट देता है। उदाहरण usages:

int main(){
    unsigned long long x = 0xABCDEF0123456789;
    printf("Before: %llX\n",x);
    REVERSE_BYTES(x);
    printf("After : %llX\n",x);

    char c[7]="nametag";
    printf("Before: %c%c%c%c%c%c%c\n",c[0],c[1],c[2],c[3],c[4],c[5],c[6]);
    REVERSE_BYTES(c);
    printf("After : %c%c%c%c%c%c%c\n",c[0],c[1],c[2],c[3],c[4],c[5],c[6]);
}

कौन सा प्रिंट:

Before: ABCDEF0123456789
After : 8967452301EFCDAB
Before: nametag
After : gateman

उपरोक्त पूरी तरह से कॉपी / पेस्ट-सक्षम है, लेकिन यहां बहुत कुछ चल रहा है, इसलिए मैं नीचे तोड़ दूँगा कि यह टुकड़े द्वारा कैसे काम करता है:

पहली उल्लेखनीय बात यह है कि एक do while(0)खंड में पूरा मैक्रो संलग्न है । यह एक सामान्य मुहावरा हैमैक्रो के बाद सामान्य अर्धविराम उपयोग की अनुमति देने के लिए है।

अगला ऊपर लूप के काउंटर के REVERSE_BYTESरूप में नामित चर का उपयोग है for। मैक्रो का नाम ही एक चर नाम के रूप में उपयोग किया जाता है ताकि यह सुनिश्चित किया जा सके कि यह किसी भी अन्य प्रतीकों के साथ नहीं टकराता है जो कि मैक्रो का उपयोग करने के लिए गुंजाइश हो सकती है। चूंकि मैक्रो के विस्तार के भीतर नाम का उपयोग किया जा रहा है, इसलिए इसे फिर से विस्तारित नहीं किया जाएगा जब यहां एक चर नाम के रूप में उपयोग किया जाता है।

forलूप के भीतर , दो बाइट्स संदर्भित किए जा रहे हैं और XOR स्वैप किए गए हैं (इसलिए एक अस्थायी चर नाम की आवश्यकता नहीं है):

((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES]
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES]

__VA_ARGS__मैक्रो को जो कुछ भी दिया गया था उसका प्रतिनिधित्व करता है, और जो पास हो सकता है उसके लचीलेपन को बढ़ाने के लिए उपयोग किया जाता है (यद्यपि बहुत से नहीं)। इस तर्क का पता तब लगाया जाता है और एक unsigned charसूचक के लिए डाली जाती है, जो सरणी ब्रीडिंग के माध्यम से अपने बाइट्स की अदला-बदली की अनुमति देता है []

अंतिम अजीब बिंदु {}ब्रेसिज़ की कमी है । वे आवश्यक नहीं हैं क्योंकि प्रत्येक स्वैप में सभी चरण अल्पविराम ऑपरेटर के साथ जुड़ जाते हैं , जिससे वे एक बयान देते हैं।

अंत में, यह ध्यान देने योग्य है कि यह आदर्श दृष्टिकोण नहीं है यदि गति एक सर्वोच्च प्राथमिकता है। यदि यह एक महत्वपूर्ण कारक है, तो अन्य उत्तरों में संदर्भित प्रकार-विशिष्ट मैक्रो या प्लेटफ़ॉर्म-विशिष्ट निर्देशों में से कुछ बेहतर विकल्प होने की संभावना है। यह दृष्टिकोण, हालांकि, सभी प्रकारों, सभी प्रमुख प्लेटफार्मों और सी और सी ++ दोनों भाषाओं के लिए पोर्टेबल है।


यह कहीं न कहीं किसी कोड में पाया गया। मुझे बाहर बिल्ली को भ्रमित कर दिया। स्पष्टीकरण के लिए धन्यवाद। हालांकि का उपयोग क्यों __VA_ARGS__?
asr9

0

वाह, मैं यहाँ पढ़े गए कुछ उत्तरों पर विश्वास नहीं कर सका। असेंबली में वास्तव में एक निर्देश है जो इसे किसी अन्य चीज़ की तुलना में तेज़ करता है। bswap। आप बस इस तरह एक समारोह लिख सकते हैं ...

__declspec(naked) uint32_t EndianSwap(uint32 value)
{
    __asm
    {
        mov eax, dword ptr[esp + 4]
        bswap eax
        ret
    }
}

यह है ज्यादा तेजी से intrinsics कि सुझाव दिया गया है की तुलना में। मैंने उन्हें डिसाइड किया और देखा। उपरोक्त फ़ंक्शन का कोई प्रस्ताव / उपसंहार नहीं है, इसलिए वस्तुतः कोई भी उपरि नहीं है।

unsigned long _byteswap_ulong(unsigned long value);

16 बिट करना उतना ही आसान है, इस अपवाद के साथ कि आप xchg al, ah का उपयोग करेंगे। bswap केवल 32-बिट रजिस्टरों पर काम करता है।

64-बिट थोड़ा और मुश्किल है, लेकिन ऐसा नहीं है। उपरोक्त सभी उदाहरणों से बेहतर है कि लूप और टेम्प्लेट आदि।

यहाँ कुछ चेतावनी हैं ... सबसे पहले bswap केवल 80x486 CPU के और इसके बाद के संस्करण पर उपलब्ध है। क्या कोई इसे 386 पर चलाने की योजना बना रहा है? यदि हां, तो आप अभी भी bswap को बदल सकते हैं ...

mov ebx, eax
shr ebx, 16
xchg bl, bh
xchg al, ah
shl eax, 16
or eax, ebx

इनलाइन असेंबली केवल Visual Studio में x86 कोड में उपलब्ध है। एक नग्न फ़ंक्शन को लाइन नहीं किया जा सकता है और यह x64 बिल्ड में भी उपलब्ध नहीं है। मुझे लगता है कि आप संकलक आंतरिक का उपयोग करने जा रहे हैं।


1
_byteswap_ulongऔर _uint64(जैसे स्वीकृत उत्तर में) दोनों bswapनिर्देश का उपयोग करने के लिए संकलित करते हैं । मुझे आश्चर्य होगा, लेकिन यह जानने में दिलचस्पी होगी कि क्या यह इतना तेज है क्योंकि यह केवल प्रस्तावना / उपसंहार को छोड़ देता है - क्या आपने इसे बेंचमार्क किया था?
ZachB

@stdcall प्रश्न ने पोर्टेबल समाधान नहीं पूछा या यहां तक ​​कि एक मंच के बारे में कुछ भी उल्लेख नहीं किया। जैसा कि मेरे जवाब में कहा गया है, ऊपर एंडियन स्वैप का सबसे तेज़ तरीका है। ज़रूर, अगर आप इसे एक गैर- x86 प्लेटफ़ॉर्म पर लिख रहे हैं, तो यह काम नहीं कर रहा है, लेकिन जैसा कि मैंने भी उल्लेख किया है, आप तब कंपाइलर इंट्रिंसिक्स तक सीमित हैं, यदि आपका कंपाइलर भी उनका समर्थन करता है।
वेल्डर

@ZachB इस विशेष मामले में, मुझे लगता है कि प्रस्तावना और उपसंहार को छोड़ना आपको एक सभ्य बचत देने जा रहा है क्योंकि आप अनिवार्य रूप से केवल 1 निर्देश पर अमल कर रहे हैं। प्रस्तावना को स्टैक पर धकेलना है, घटाव करना है, बेस-पॉइंटर सेट करना है और फिर अंत में समान है। मैंने इसे बेंचमार्क नहीं किया है, लेकिन ऊपर एक 0 निर्भरता श्रृंखला है जो आप बस नग्न होने के बिना नहीं जा रहे हैं। हो सकता है कि एक अच्छा संकलक इसे इनलाइन कर दे, लेकिन फिर आप एक अलग बॉल-पार्क में हैं।
वेल्डर

2
शायद। लेकिन ध्यान दें कि संख्याओं की एक सरणी को स्वैप करने के सामान्य मामले में, अन्य उत्तरों में चर्चा किए गए संकलक आंतरिक एसएसई / एवीएक्स एक्सटेंशन का उपयोग करेंगे और PSHUFB का उत्सर्जन करेंगे, जो बीएसडब्ल्यूएपी को मात देते हैं। देखें wm.ite.pl/articles/reverse-array-of-bytes.html
ZachB

यह एक मंच-विशिष्ट समाधान पोस्ट करने के लिए IMHO बुरा रूप है, जब ओपी ने यह निर्दिष्ट नहीं किया कि उन्हें केवल x86 के समाधान की आवश्यकता है। और अन्य समाधानों को अलग करने के लिए, जब आपका बहुत ही व्यापक रूप से उपयोग किए जाने वाले OS जैसे iOS और Android (जो ARM या MIPS CPU का उपयोग करते हैं) पर
अनुपयोगी है

0

ऑप्टिमाइज़र-फ्रेंडली अनलॉग्ड नॉन-इनलेस एंडियन एक्सेसर्स को लागू करने के लिए पोर्टेबल तकनीक। वे हर संकलक, प्रत्येक सीमा संरेखण और हर बाइट क्रम पर काम करते हैं। देशी एंडियन और संरेखण पर निर्भर करते हुए, ये अन-असाइन किए गए रूटीन पूरक, या लूटे गए हैं। आंशिक लिस्टिंग लेकिन आपको यह विचार मिलता है। बीओ * देशी बाइट ऑर्डर के आधार पर निरंतर मूल्य हैं।

uint32_t sw_get_uint32_1234(pu32)
uint32_1234 *pu32;
{
  union {
    uint32_1234 u32_1234;
    uint32_t u32;
  } bou32;
  bou32.u32_1234[0] = (*pu32)[BO32_0];
  bou32.u32_1234[1] = (*pu32)[BO32_1];
  bou32.u32_1234[2] = (*pu32)[BO32_2];
  bou32.u32_1234[3] = (*pu32)[BO32_3];
  return(bou32.u32);
}

void sw_set_uint32_1234(pu32, u32)
uint32_1234 *pu32;
uint32_t u32;
{
  union {
    uint32_1234 u32_1234;
    uint32_t u32;
  } bou32;
  bou32.u32 = u32;
  (*pu32)[BO32_0] = bou32.u32_1234[0];
  (*pu32)[BO32_1] = bou32.u32_1234[1];
  (*pu32)[BO32_2] = bou32.u32_1234[2];
  (*pu32)[BO32_3] = bou32.u32_1234[3];
}

#if HAS_SW_INT64
int64 sw_get_int64_12345678(pi64)
int64_12345678 *pi64;
{
  union {
    int64_12345678 i64_12345678;
    int64 i64;
  } boi64;
  boi64.i64_12345678[0] = (*pi64)[BO64_0];
  boi64.i64_12345678[1] = (*pi64)[BO64_1];
  boi64.i64_12345678[2] = (*pi64)[BO64_2];
  boi64.i64_12345678[3] = (*pi64)[BO64_3];
  boi64.i64_12345678[4] = (*pi64)[BO64_4];
  boi64.i64_12345678[5] = (*pi64)[BO64_5];
  boi64.i64_12345678[6] = (*pi64)[BO64_6];
  boi64.i64_12345678[7] = (*pi64)[BO64_7];
  return(boi64.i64);
}
#endif

int32_t sw_get_int32_3412(pi32)
int32_3412 *pi32;
{
  union {
    int32_3412 i32_3412;
    int32_t i32;
  } boi32;
  boi32.i32_3412[2] = (*pi32)[BO32_0];
  boi32.i32_3412[3] = (*pi32)[BO32_1];
  boi32.i32_3412[0] = (*pi32)[BO32_2];
  boi32.i32_3412[1] = (*pi32)[BO32_3];
  return(boi32.i32);
}

void sw_set_int32_3412(pi32, i32)
int32_3412 *pi32;
int32_t i32;
{
  union {
    int32_3412 i32_3412;
    int32_t i32;
  } boi32;
  boi32.i32 = i32;
  (*pi32)[BO32_0] = boi32.i32_3412[2];
  (*pi32)[BO32_1] = boi32.i32_3412[3];
  (*pi32)[BO32_2] = boi32.i32_3412[0];
  (*pi32)[BO32_3] = boi32.i32_3412[1];
}

uint32_t sw_get_uint32_3412(pu32)
uint32_3412 *pu32;
{
  union {
    uint32_3412 u32_3412;
    uint32_t u32;
  } bou32;
  bou32.u32_3412[2] = (*pu32)[BO32_0];
  bou32.u32_3412[3] = (*pu32)[BO32_1];
  bou32.u32_3412[0] = (*pu32)[BO32_2];
  bou32.u32_3412[1] = (*pu32)[BO32_3];
  return(bou32.u32);
}

void sw_set_uint32_3412(pu32, u32)
uint32_3412 *pu32;
uint32_t u32;
{
  union {
    uint32_3412 u32_3412;
    uint32_t u32;
  } bou32;
  bou32.u32 = u32;
  (*pu32)[BO32_0] = bou32.u32_3412[2];
  (*pu32)[BO32_1] = bou32.u32_3412[3];
  (*pu32)[BO32_2] = bou32.u32_3412[0];
  (*pu32)[BO32_3] = bou32.u32_3412[1];
}

float sw_get_float_1234(pf)
float_1234 *pf;
{
  union {
    float_1234 f_1234;
    float f;
  } bof;
  bof.f_1234[0] = (*pf)[BO32_0];
  bof.f_1234[1] = (*pf)[BO32_1];
  bof.f_1234[2] = (*pf)[BO32_2];
  bof.f_1234[3] = (*pf)[BO32_3];
  return(bof.f);
}

void sw_set_float_1234(pf, f)
float_1234 *pf;
float f;
{
  union {
    float_1234 f_1234;
    float f;
  } bof;
  bof.f = (float)f;
  (*pf)[BO32_0] = bof.f_1234[0];
  (*pf)[BO32_1] = bof.f_1234[1];
  (*pf)[BO32_2] = bof.f_1234[2];
  (*pf)[BO32_3] = bof.f_1234[3];
}

double sw_get_double_12345678(pd)
double_12345678 *pd;
{
  union {
    double_12345678 d_12345678;
    double d;
  } bod;
  bod.d_12345678[0] = (*pd)[BO64_0];
  bod.d_12345678[1] = (*pd)[BO64_1];
  bod.d_12345678[2] = (*pd)[BO64_2];
  bod.d_12345678[3] = (*pd)[BO64_3];
  bod.d_12345678[4] = (*pd)[BO64_4];
  bod.d_12345678[5] = (*pd)[BO64_5];
  bod.d_12345678[6] = (*pd)[BO64_6];
  bod.d_12345678[7] = (*pd)[BO64_7];
  return(bod.d);
}

void sw_set_double_12345678(pd, d)
double_12345678 *pd;
double d;
{
  union {
    double_12345678 d_12345678;
    double d;
  } bod;
  bod.d = d;
  (*pd)[BO64_0] = bod.d_12345678[0];
  (*pd)[BO64_1] = bod.d_12345678[1];
  (*pd)[BO64_2] = bod.d_12345678[2];
  (*pd)[BO64_3] = bod.d_12345678[3];
  (*pd)[BO64_4] = bod.d_12345678[4];
  (*pd)[BO64_5] = bod.d_12345678[5];
  (*pd)[BO64_6] = bod.d_12345678[6];
  (*pd)[BO64_7] = bod.d_12345678[7];
}

यदि इन एक्सेसर्स के साथ उपयोग नहीं किया जाता है, तो इन टाइपडिफ को कंपाइलर त्रुटियों को बढ़ाने का लाभ होता है, इस प्रकार भूल गए एक्सेस बग को कम किया जाता है।

typedef char int8_1[1], uint8_1[1];

typedef char int16_12[2], uint16_12[2]; /* little endian */
typedef char int16_21[2], uint16_21[2]; /* big endian */

typedef char int24_321[3], uint24_321[3]; /* Alpha Micro, PDP-11 */

typedef char int32_1234[4], uint32_1234[4]; /* little endian */
typedef char int32_3412[4], uint32_3412[4]; /* Alpha Micro, PDP-11 */
typedef char int32_4321[4], uint32_4321[4]; /* big endian */

typedef char int64_12345678[8], uint64_12345678[8]; /* little endian */
typedef char int64_34128756[8], uint64_34128756[8]; /* Alpha Micro, PDP-11 */
typedef char int64_87654321[8], uint64_87654321[8]; /* big endian */

typedef char float_1234[4]; /* little endian */
typedef char float_3412[4]; /* Alpha Micro, PDP-11 */
typedef char float_4321[4]; /* big endian */

typedef char double_12345678[8]; /* little endian */
typedef char double_78563412[8]; /* Alpha Micro? */
typedef char double_87654321[8]; /* big endian */

2
इस प्रश्न के लिए, C ++ टैग से फर्क पड़ता है। C ++ और संघ के कारण बहुत सारे अपरिभाषित व्यवहार हैं।
jww

0

यहां बताया गया है कि आईईईई 754 64 बिट प्रारूप में एक डबल संग्रहीत कैसे पढ़ा जाए, भले ही आपका मेजबान कंप्यूटर एक अलग प्रणाली का उपयोग करता हो।

/*
* read a double from a stream in ieee754 format regardless of host
*  encoding.
*  fp - the stream
*  bigendian - set to if big bytes first, clear for little bytes
*              first
*
*/
double freadieee754(FILE *fp, int bigendian)
{
    unsigned char buff[8];
    int i;
    double fnorm = 0.0;
    unsigned char temp;
    int sign;
    int exponent;
    double bitval;
    int maski, mask;
    int expbits = 11;
    int significandbits = 52;
    int shift;
    double answer;

    /* read the data */
    for (i = 0; i < 8; i++)
        buff[i] = fgetc(fp);
    /* just reverse if not big-endian*/
    if (!bigendian)
    {
        for (i = 0; i < 4; i++)
        {
            temp = buff[i];
            buff[i] = buff[8 - i - 1];
            buff[8 - i - 1] = temp;
        }
    }
    sign = buff[0] & 0x80 ? -1 : 1;
    /* exponet in raw format*/
    exponent = ((buff[0] & 0x7F) << 4) | ((buff[1] & 0xF0) >> 4);

    /* read inthe mantissa. Top bit is 0.5, the successive bits half*/
    bitval = 0.5;
    maski = 1;
    mask = 0x08;
    for (i = 0; i < significandbits; i++)
    {
        if (buff[maski] & mask)
            fnorm += bitval;

        bitval /= 2.0;
        mask >>= 1;
        if (mask == 0)
        {
            mask = 0x80;
            maski++;
        }
    }
    /* handle zero specially */
    if (exponent == 0 && fnorm == 0)
        return 0.0;

    shift = exponent - ((1 << (expbits - 1)) - 1); /* exponent = shift + bias */
    /* nans have exp 1024 and non-zero mantissa */
    if (shift == 1024 && fnorm != 0)
        return sqrt(-1.0);
    /*infinity*/
    if (shift == 1024 && fnorm == 0)
    {

#ifdef INFINITY
        return sign == 1 ? INFINITY : -INFINITY;
#endif
        return  (sign * 1.0) / 0.0;
    }
    if (shift > -1023)
    {
        answer = ldexp(fnorm + 1.0, shift);
        return answer * sign;
    }
    else
    {
        /* denormalised numbers */
        if (fnorm == 0.0)
            return 0.0;
        shift = -1022;
        while (fnorm < 1.0)
        {
            fnorm *= 2;
            shift--;
        }
        answer = ldexp(fnorm, shift);
        return answer * sign;
    }
}

बाकी कार्यों के लिए, जिसमें लेखन और पूर्णांक दिनचर्या शामिल हैं, मेरी गितुब परियोजना देखें

https://github.com/MalcolmMcLean/ieee754


0

टेम्पलेट फंक्शन में धुरी के चारों ओर तु ओल्ड 3-स्टेप-एक्सोर ट्रिक के साथ बाइट स्वैपिंग एक लचीला, त्वरित ओ (ln2) समाधान देता है जिसमें लाइब्रेरी की आवश्यकता नहीं होती है, यहां शैली 1 बाइट प्रकारों को भी अस्वीकार करती है:

template<typename T>void swap(T &t){
    for(uint8_t pivot = 0; pivot < sizeof(t)/2; pivot ++){
        *((uint8_t *)&t + pivot) ^= *((uint8_t *)&t+sizeof(t)-1- pivot);
        *((uint8_t *)&t+sizeof(t)-1- pivot) ^= *((uint8_t *)&t + pivot);
        *((uint8_t *)&t + pivot) ^= *((uint8_t *)&t+sizeof(t)-1- pivot);
    }
}

0

लगता है कि प्रत्येक शब्द पर htons का उपयोग करने का सुरक्षित तरीका होगा। इसलिए, यदि आपके पास ...

std::vector<uint16_t> storage(n);  // where n is the number to be converted

// the following would do the trick
std::transform(word_storage.cbegin(), word_storage.cend()
  , word_storage.begin(), [](const uint16_t input)->uint16_t {
  return htons(input); });

यदि आप एक बड़े-एंडियन सिस्टम पर थे, तो उपरोक्त एक नो-ऑप होगा, इसलिए मैं यह समझने के लिए कि आपके प्लेटफॉर्म एक संकलन-समय की स्थिति के रूप में उपयोग करते हैं, यह तय करने के लिए कि क्या htons एक ऑप-ऑप है। यह सब के बाद O (n) है। एक मैक पर, यह कुछ इस तरह होगा ...

#if (__DARWIN_BYTE_ORDER != __DARWIN_BIG_ENDIAN)
std::transform(word_storage.cbegin(), word_storage.cend()
  , word_storage.begin(), [](const uint16_t input)->uint16_t {
  return htons(input); });
#endif

0

अगर आपके पास C ++ 17 है तो इस हैडर को जोड़ें

#include <algorithm>

बाइट्स स्वैप करने के लिए इस टेम्प्लेट फ़ंक्शन का उपयोग करें:

template <typename T>
void swapEndian(T& buffer)
{
    static_assert(std::is_pod<T>::value, "swapEndian support POD type only");
    char* startIndex = static_cast<char*>((void*)buffer.data());
    char* endIndex = startIndex + sizeof(buffer);
    std::reverse(startIndex, endIndex);
}

इसे कॉल करें:

swapEndian (stlContainer);

-4

थोड़ा ऊपर की ओर देखें, क्योंकि यह मूल रूप से आपको छोटे -> बड़े एंडियन से स्वैप करने की आवश्यकता है। फिर बिट आकार के आधार पर, आप बदलते हैं कि आप बिट शिफ्टिंग कैसे करते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.