قراءة البيانات الثنائية المعبأة 32 بت على نظام 64 بت

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

  •  02-07-2019
  •  | 
  •  

سؤال

أحاول كتابة امتداد Python C الذي يقرأ البيانات الثنائية المعبأة (يتم تخزينها على هيئة بنيات) ثم يقوم بتحليلها إلى كائنات Python.كل شيء يعمل كما هو متوقع على جهاز 32 بت (تتم كتابة الملفات الثنائية دائمًا على بنية 32 بت)، ولكن ليس على جهاز 64 بت.هل هناك طريقة "مفضلة" للقيام بذلك؟


سيكون هناك الكثير من التعليمات البرمجية للنشر ولكن كمثال:

struct
{
    WORD    version;
    BOOL    upgrade;
    time_t  time1;
            time_t  time2;
} apparms;

File *fp;
fp = fopen(filePath, "r+b");
fread(&apparms, sizeof(apparms), 1, fp);
return Py_BuildValue("{s:i,s:l,s:l}",
  "sysVersion",apparms.version,
  "powerFailTime", apparms.time1,
  "normKitExpDate", apparms.time2
 );

الآن يعمل هذا بشكل رائع على نظام 32 بت، ولكن على نظام 64 بت تختلف أحجام time_t (32 بت مقابل 64 بت).


اللعنة، أيها الناس سريعون.

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

أعلم أن هذا سؤال غبي ولكن ما هي الأنواع التي يجب أن أحذر منها؟

شكرًا.

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

المحلول

حدد بوضوح أن أنواع البيانات الخاصة بك (على سبيل المثال:الأعداد الصحيحة) هي 32 بت.بخلاف ذلك، إذا كان لديك عددان صحيحان بجوار بعضهما البعض عند قراءتهما، فسيتم قراءتهما كعدد صحيح واحد بطول 64 بت.

عندما تتعامل مع مشكلات عبر الأنظمة الأساسية، فإن الأمرين الرئيسيين اللذين يجب الانتباه إليهما هما:

  1. بيتنس.إذا كانت بياناتك المجمعة مكتوبة باستخدام ints 32 بت، فيجب أن تحدد جميع التعليمات البرمجية الخاصة بك بشكل صريح 32 بت ints عند القراءة و كتابة.
  2. ترتيب البايت.إذا قمت بنقل التعليمات البرمجية الخاصة بك من شرائح Intel إلى PPC أو SPARC، فسيكون ترتيب البايت الخاص بك خاطئًا.سيتعين عليك استيراد بياناتك ثم قلبها بحيث تتوافق مع البنية الحالية.وإلا 12(0x0000000C) ستتم قراءتها كـ 201326592 (0x0C000000).

نأمل أن يساعد هذا.

نصائح أخرى

يجب أن تكون وحدة "البنية" قادرة على القيام بذلك، على الرغم من أن محاذاة البنيات في منتصف البيانات يمثل دائمًا مشكلة.ومع ذلك، ليس من الصعب جدًا القيام بذلك بشكل صحيح:اكتشف (مرة واحدة) الحدود التي تتماشى معها الهياكل في الهياكل، ثم قم بوضعها (يدويًا باستخدام محدد "x") على تلك الحدود.يمكنك التحقق مرة أخرى من المساحة المتروكة لديك من خلال مقارنة struct.calcsize() ببياناتك الفعلية.إنه بالتأكيد أسهل من كتابة ملحق C له.

من أجل الاستمرار في استخدام Py_BuildValue() بهذه الطريقة، لديك خياران.يمكنك تحديد حجم time_t في وقت التحويل البرمجي (من حيث الأنواع الأساسية، لذلك "an int" أو "a long" أو "an ssize_t") ثم استخدام حرف التنسيق الصحيح لـ Py_BuildValue - "i" لـ int، "l" لفترة طويلة، و"n" لـ ssize_t.أو يمكنك استخدام PyInt_FromSsize_t() يدويًا، وفي هذه الحالة يقوم المترجم بالترقية نيابةً عنك، ثم استخدم أحرف التنسيق "O" لتمرير النتيجة إلى Py_BuildValue.

يجب عليك التأكد من أنك تستخدم أعضاء مستقلين في البنية الخاصة بك.على سبيل المثال، قد يكون int 32 بت على بنية واحدة و64 بت على بنية أخرى.كما اقترح آخرون، استخدم int32_t أنواع الأنماط بدلاً من ذلك.إذا كانت البنية الخاصة بك تحتوي على أعضاء غير محاذيين، فقد تحتاج إلى التعامل مع الحشو الذي أضافه المترجم أيضًا.

هناك مشكلة شائعة أخرى تتعلق ببيانات البنية المتقاطعة وهي endianness.تعتبر بنية Intel i386 صغيرة الحجم، ولكن إذا كنت تقرأ على جهاز مختلف تمامًا (على سبيل المثال،Alpha أو Sparc)، يجب أن تقلق بشأن هذا أيضًا.

تتعامل وحدة بنية Python مع كلتا الحالتين، باستخدام البادئة التي تم تمريرها كجزء من سلسلة التنسيق.

  • @ - استخدم الحجم الأصلي والنهاية والمحاذاة.أنا= sizeof(int)، ل= sizeof(طويل)
  • = - استخدم endianness الأصلي، ولكن الأحجام القياسية والمحاذاة (i=32 بت، l=64 بت)
  • < - الأحجام/المحاذاة القياسية ذات النهاية الصغيرة
    • الأحجام/المحاذاة القياسية ذات النهاية الكبيرة

بشكل عام، إذا مرت البيانات من جهازك، فيجب عليك تحديد النهاية وتنسيق الحجم/الحشو إلى شيء محدد - على سبيل المثال.استخدم "<" أو ">" كتنسيق خاص بك.إذا كنت تريد التعامل مع هذا في ملحق C الخاص بك، فقد تحتاج إلى إضافة بعض التعليمات البرمجية للتعامل معه.

ما هو الكود الخاص بك لقراءة البيانات الثنائية؟تأكد من نسخ البيانات إلى أنواع ذات حجم مناسب مثل int32_t بدلا من مجرد int.

لماذا لا تستخدم البنية طَرد؟

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