سؤال

لدي قيمة عدد صحيح طويل غير موقعة تمثل تعويم باستخدام تنسيق IEEE-754. ما هي أسرع طريقة لطباعةها كطويلة في C ++؟

أعرف طريقة واحدة، لكنني أتساءل عما إذا كانت هناك فائدة مريحة في C ++ التي ستكون أفضل.

مثال على الطريقة التي أعرفها هي:

union
{
    unsigned long ul;
    float f;
} u;

u.ul = 1084227584; // in HEX, this is 0x40A00000

cout << "float value is: " << u.f << endl;

(هذا يطبع "قيمة تعويم هو: 5")

هل كانت مفيدة؟

المحلول

طريقة النقابة التي اقترحتها هي الطريق المعتاد الذي سيستغرقه معظم الناس. ومع ذلك، إنه من الناحية الفنية السلوك غير محدد في C / C ++ لقراءة عضو مختلف من اتحاد من النقطة التي تم كتابتها مؤخرا. على الرغم من ذلك، على الرغم من ذلك، فإنه مدعوم جيدا بين جميع المترجمين.

مؤشرات الصب، كما اقترح جون سكيت, ، فكرة سيئة - التي تنتهك التعرج الصارم قواعد C. لنتج برنامج التحويل البرمجي العدواني رمز غير صحيح لذلك، لأنه يفترض أن مؤشرات الأنواع unsigned long * و float * لن الاسم الآخر أبدا.

الطريقة الأكثر صحة، من حيث الامتثال للمعايير (أي، لا تستجع السلوك غير المحدد)، هو الإدلاء من خلال char*, ، لأن قواعد التعرج الصارمة تسمح char* مؤشر إلى الاسم المستعار مؤشر لأي نوع آخر:

unsigned long ul = 0x40A00000;
float f;
char *pul = (char *)&ul;  // ok, char* can alias any type
char *pf = (char *)&f;    // ok, char* can alias any type
memcpy(pf, pul, sizeof(float));

على الرغم من بصراحة، أود فقط أن أذهب مع طريقة النقابة. من رابط cellperformance.com أعلاه:

إنه مصبوما شائع للغاية ويتم دعمه جيدا من قبل جميع المجمعين الرئيسيين. كمسألة عملية، القراءة والكتابة إلى أي عضو في الاتحاد، بأي ترتيب، هي ممارسة مقبولة.

نصائح أخرى

لن يعمل فقط على آلات أو آلات 32 بت حيث مقايف (طويل) == SIVEFOF (تعويم). على الآلات الحديثة، قد ترغب في استخدام int بدلا من ذلك ... وعليك حقا الاعتناء إذا كنت تقوم بأداء هذه الخدعة.

كنت أفكر في نفس الشيء مثل Jon Skeet، لكنه فازني عليه. ومع ذلك، أود أن أفعل ذلك أكثر إغاثة قليلا مما فعله.

cout << "float value is: " << *((float *) &ulValue)) << endl;

يمكنك الحصول على مؤشر لك منذ فترة طويلة، ثم إعادة تفسير أنه كمأشر تعويم، ثم قم بإلغاء تحديد مؤشرك لتطفو تنتج قيمة تعويم.

نظرا لأنك تقوم بعمل هذا في C ++، فهو أكثر وضوحا لاستخدام إعادة تتريت DESTERPRET_CLAST بدلا من يلقي نمط C القديم.

cout << "float value is: " << *(reinterpret_cast<float *>(&ulValue)) << endl;

تحرير: لقد اعتقدت سابقا أن هذا كان "سيئة فقط"، لكنه اتضح أن يكون أسوأ مما كنت أعتقد - انظر التعليقات للحصول على التفاصيل. لن أوصي بهذا النهج، لكنني سأترك الأمر هنا لتوثيق الاحتمال (وتحذير!)


يمكنك استخدام المؤشرات:

long ul = 1084227584;
float* fp = (float*) &ul;
float f = *fp;

(يمكن أن يكون هذا مكثفا في سطر واحد، لكنني أعتقد أنه أكثر وضوحا لا.)

في الأساس نفس الشيء مثل نقابك ... والمراوغة على قدم المساواة إلا إذا كنت متأكدا من أحجام الأنواع المعنية.

إذا كانت منصةك تدعمها، فربما يجب عليك استخدام أسماء أنواع الحجم الخاصة بالحجم لكل من أنواع النقطة العالية والعائمة.

كان SWEGI الاتجاه الصحيح، لكنه غاب عن حرف واحد. الطريقة الصحيحة هي

long l = 1084227584L
float f = reinterpret_cast<float&>(l);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top