هل هناك أي وظيفة "قياسية" تشبه HTONL لـ 64 بت أعداد صحيحة في C ++؟

StackOverflow https://stackoverflow.com/questions/3022552

سؤال

أنا أعمل على تنفيذ بروتوكول Memcache الذي يستخدم في بعض النقاط 64 بتات عدد صحيح. يجب تخزين هذه القيم في "ترتيب بايت الشبكة".

أتمنى لو كان هناك بعض uint64_t htonll(uint64_t value) وظيفة لإجراء التغيير ، ولكن لسوء الحظ ، إذا كان موجودًا ، لم أتمكن من العثور عليه.

لذلك لدي سؤال واحد أو 2:

  • هل هنالك أي محمول (Windows ، Linux ، AIX) وظيفة قياسية للقيام بذلك؟
  • إذا لم تكن هناك وظيفة من هذا القبيل ، كيف يمكنك تنفيذها؟

لقد وضعت في اعتبارك تطبيقًا أساسيًا ، لكنني لا أعرف كيفية التحقق من endianness في وقت الترجمة لجعل الكود محمول. لذا فإن مساعدتك أكثر من موضع ترحيب هنا ؛)

شكرًا لك.


إليكم الحل النهائي الذي كتبته ، بفضل حل براين.

uint64_t htonll(uint64_t value)
{
    // The answer is 42
    static const int num = 42;

    // Check the endianness
    if (*reinterpret_cast<const char*>(&num) == num)
    {
        const uint32_t high_part = htonl(static_cast<uint32_t>(value >> 32));
        const uint32_t low_part = htonl(static_cast<uint32_t>(value & 0xFFFFFFFFLL));

        return (static_cast<uint64_t>(low_part) << 32) | high_part;
    } else
    {
        return value;
    }
}
هل كانت مفيدة؟

المحلول

ربما تبحث عنه bswap_64 أعتقد أنه مدعوم إلى حد كبير في كل مكان ولكني لن أسميه قياسيًا.

يمكنك بسهولة التحقق من endianness عن طريق إنشاء int بقيمة 1 ، وإلقاء عنوان int الخاص بك كملف char* والتحقق من قيمة البايت الأول.

علي سبيل المثال:

int num = 42;
if(*(char *)&num == 42)
{
   //Little Endian
}
else
{
   //Big Endian
} 

مع العلم أن يمكنك أيضًا عمل وظيفة بسيطة تقوم بالمبادلة.


يمكنك أيضًا استخدام Boost دائمًا الذي يحتوي على وحدات الماكرو الإنديان التي هي منصة متقاطعة محمولة.

نصائح أخرى

#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))

الاختبار (1 == htonl (1)) يحدد ببساطة (في وقت التشغيل للأسف) إذا كانت بايت بنية الأجهزة تبديل بايت. لا توجد أي طرق محمولة لتحديد وقت الترجمة ماهية البنية ، لذلك نلجأ إلى استخدام "Htonl" ، وهو محمول كما هو الحال في هذا الموقف. إذا كانت هناك حاجة إلى تبادل البايت ، فنحن نقوم بتبديل 32 بت في وقت واحد باستخدام HTONL (نتذكر تبديل كلمتين 32 بت أيضًا).


فيما يلي طريقة أخرى لإجراء المبادلة المحمولة عبر معظم المجمعين وأنظمة التشغيل ، بما في ذلك AIX و BSDs و Linux و Solaris.

#if __BIG_ENDIAN__
# define htonll(x) (x)
# define ntohll(x) (x)
#else
# define htonll(x) ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
# define ntohll(x) ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
#endif

الجزء المهم هو الاستخدام __BIG_ENDIAN__ أو __LITTLE_ENDIAN__; ؛ و لا __BYTE_ORDER__, __ORDER_BIG_ENDIAN__ أو __ORDER_LITTLE_ENDIAN__. يفتقر بعض المجمعين وأنظمة التشغيل __BYTE_ORDER__ والأصدقاء.

يمكنك المحاولة uint64_t htobe64(uint64_t host_64bits) & uint64_t be64toh(uint64_t big_endian_64bits) للعكس بالعكس.

يبدو أن هذا يعمل في ج. هل قمت بأي تصرف خاطئ؟

uint64_t htonll(uint64_t value) {
    int num = 42;
    if (*(char *)&num == 42) {
        uint32_t high_part = htonl((uint32_t)(value >> 32));
        uint32_t low_part = htonl((uint32_t)(value & 0xFFFFFFFFLL));
        return (((uint64_t)low_part) << 32) | high_part;
    } else {
        return value;
    }
}

لتقليل النفقات العامة لـ "if num == ..." ، استخدم المعالج المسبق:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#else
#endif

تحرير: الجمع بين الاثنين (كود براين المستخدم):

uint64_t htonll(uint64_t value)
{
     int num = 42;
     if(*(char *)&num == 42)
          return (htonl(value & 0xFFFFFFFF) << 32LL) | htonl(value >> 32);
     else 
          return value;
}

تحذير: رمز لم يخبر! الرجاء الاختبار قبل استخدام.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top