مبادلة بت في C ++ لمضاعفة
-
28-09-2019 - |
سؤال
أنا أحاول التغيير من Big Endian إلى Little Endian على مضاعفة. طريقة واحدة للذهاب هي الاستخدام
double val, tmp = 5.55;
((unsigned int *)&val)[0] = ntohl(((unsigned int *)&tmp)[1]);
((unsigned int *)&val)[1] = ntohl(((unsigned int *)&tmp)[0]);
ولكن بعد ذلك أحصل على تحذير: "إن التخلص من المؤشر الذي تم ربطه من النوع سوف يكسر القواعد الصارمة للتخلي" ولا أريد إيقاف هذا التحذير.
طريقة أخرى للذهاب هي:
#define ntohll(x) ( ( (uint64_t)(ntohl( (uint32_t)((x << 32) >> 32) )) << 32) | ntohl( ((uint32_t)(x >> 32)) ) )
val = (double)bswap_64(unsigned long long(tmp)); //or
val = (double)ntohll(unsigned long long(tmp));
ولكن بعد ذلك يفقد العشرية. أي شخص يعرف طريقة جيدة لمبادلة البتات على مضاعفة دون استخدام حلقة؟
المحلول
ربما أحاول شيئًا كهذا:
template <typename T>
void swap_endian(T& pX)
{
// should static assert that T is a POD
char& raw = reinterpret_cast<char&>(pX);
std::reverse(&raw, &raw + sizeof(T));
}
قصيرة وحلوة (وغير المختبرة نسبيا). سوف يقوم المترجم بجميع التحسينات اللازمة. ما سبق محدد جيدًا لأي نوع من أنواع القرنة ، ولا يعتمد على أي تفاصيل تنفيذ.
نسخة نسخ ، عندما لا تريد تعديل الوسيطة:
template <typename T>
T swap_endian_copy(T pX)
{
swap_endian(pX);
return pX;
}
نصائح أخرى
هناك بعض المزالق المهمة للانتباه إليها عند التعامل مع التمثيل الثنائي للعوامات أو الزوجي.
ألا يمكنك فقط تبديلهم؟
inline unsigned long long EndianChange( double d )
{
char ch[8];
memcpy( ch, &d, 8 ); // Note this will be optimised out completely by pretty much every compiler.
ch[0] ^= ch[7] ^= ch[0] ^= ch[7];
ch[1] ^= ch[6] ^= ch[1] ^= ch[6];
ch[2] ^= ch[5] ^= ch[2] ^= ch[5];
ch[3] ^= ch[4] ^= ch[3] ^= ch[4];
unsigned long long dRet;
memcpy( &dRet, ch, 8 ); // Again this will get optimised out.
return dRet;
};
تحرير: كما أشار إلى أن البايت المتبادلة مزدوجة "يمكن أن يتم تحميلها في سجل بحيث يمكن أن يعود إخراجها من هذا السجل إلى أن القيمة لم تعد صالحة ، لذا تخزينها في فترة طويلة طويلة و 64 بت لتجنب هذه المشكلة.
هذا هو كل ما هناك إلى مبادلة بايت. لست متأكدًا مما تحاول القيام به ، لكن كل منصة endian كبيرة استخدمتها تستخدم نفس الترميز مثل Little-Indian فقط ترتيب البايت. سوف يعكس الرمز أعلاه ترتيب البايت لك. إلى حد كبير ، سيقوم أي مترجم ببساطة بمبادلة البايت ثم إعادة البايت المتغير المتبادل والتخلص من memcpys. هذه طريقة جيدة للتعامل مع قضايا التعرج.