سؤال

أقوم بنقل تطبيق إلى منصة ARM في C ، ويعمل التطبيق أيضًا على معالج X86 ، ويجب أن يكون متوافقًا للخلف.

لدي الآن بعض المشكلات مع المحاذاة المتغيرة. لقد قرأت دليل دول مجلس التعاون الخليجي ل__attribute__((aligned(4),packed)) أفسر ما يقال مع بدء بداية الهيكل مع Bittle Bittle 4 والداخل لا يزال دون أن يمس بسبب البيان المعبأ.

في الأصل كان لدي هذا ، لكن في بعض الأحيان يتم وضعه بدون محاذاة مع حدود البايت 4.

typedef struct  
{  
 unsigned int code;  
 unsigned int length;  
 unsigned int seq;  
 unsigned int request;  
 unsigned char nonce[16];  
 unsigned short  crc;  
} __attribute__((packed)) CHALLENGE;

لذلك أقوم بتغييره إلى هذا.

typedef struct  
{  
 unsigned int code;  
 unsigned int length;  
 unsigned int seq;  
 unsigned int request;  
 unsigned char nonce[16];  
 unsigned short  crc;  
} __attribute__((aligned(4),packed)) CHALLENGE;

يبدو أن الفهم الذي ذكرته في وقت سابق غير صحيح لأن كلا الهيكل يتوافق الآن مع حدود 4 بايت ، ويتم الآن محاذاة البيانات الداخلية مع حدود بايت أربعة ، ولكن بسبب endianess ، زاد حجم الهيكل في الحجم من 42 إلى 44 بايت. هذا الحجم أمر بالغ الأهمية لأن لدينا تطبيقات أخرى تعتمد على البنية هي 42 بايت.

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

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

المحلول

إذا كنت تعتمد على sizeof(yourstruct) كونها 42 بايت ، فأنت على وشك أن تتعرض للعض من قبل عالم من الافتراضات غير المحمولة. لم تقل ما هو عليه ، ولكن يبدو من المحتمل أن يكون Endianness of the Struct Contents مهمًا أيضًا ، لذلك قد يكون لديك أيضًا عدم تطابق مع X86 هناك أيضًا.

في هذه الحالة ، أعتقد أن الطريقة الوحيدة المؤكدة للتغلب عليها هي الاستخدام unsigned char[42] في الأجزاء التي يهم. ابدأ بكتابة مواصفات دقيقة لماهية الحقول بالضبط في هذه الكتلة 42 بايت ، وما هو Endian ، ثم استخدم هذا التعريف لكتابة بعض التعليمات البرمجية لترجمتها بين ذلك والبنية التي يمكنك التفاعل معها. من المحتمل أن يكون الرمز إما رمز التسلسل بالكامل (ويعرف أيضًا باسم Markalling) ، أو مجموعة من Getters و Petters.

نصائح أخرى

هذا هو أحد الأسباب التي تجعل قراءة الهياكل بأكملها بدلاً من فشل العضو ، ويجب تجنبها.

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

أتصور أن لديك شيء مثل:

read(fd, &obj, sizeof obj)

لأنك لا ترغب في قراءة بايت الحشوة اللذين ينتميان إلى بيانات مختلفة ، يجب عليك تحديد الحجم بشكل صريح:

read(fd, &obj, 42)

الذي يمكنك الحفاظ عليه قابلة للصيانة:

typedef struct {
  //...
  enum { read_size = 42 };
} __attribute__((aligned(4),packed)) CHALLENGE;

// ...

read(fd, &obj, obj.read_size)

أو ، إذا لم تتمكن من استخدام بعض ميزات C ++ في C:

typedef struct {
  //...
} __attribute__((aligned(4),packed)) CHALLENGE;
enum { CHALLENGE_read_size = 42 };

// ...

read(fd, &obj, CHALLENGE_read_size)

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

ما هو هدفك الحقيقي؟

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

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

لقد قمت بنقل الهياكل ذهابًا وإيابًا من Linux و Windows و Mac و C و Swift والتجميع ، إلخ.

المشكلة ليست أنه لا يمكن القيام بها ، المشكلة هي أنه لا يمكنك أن تكون كسولًا ويجب أن تفهم أدواتك.

لا أرى لماذا لا يمكنك استخدام:

typedef struct  
{  
 unsigned int code;  
 unsigned int length;  
 unsigned int seq;  
 unsigned int request;  
 unsigned char nonce[16];  
 unsigned short  crc;  
} __attribute__((packed)) CHALLENGE;

أنت يستطيع استخدمه ولا يتطلب أي رمز خاص أو ذكي. أكتب الكثير من التعليمات البرمجية التي تتواصل لتسليح. الهياكل هي التي تجعل الأشياء تعمل. __attribute__ ((packed)) هو صديقي.

احتمالات التواجد في "عالم الأذى" هي لا شيء إذا فهمت ما يجري مع كليهما.

أخيرًا ، لا يمكنني أن أوضح مدى الحياة كيف تحصل على 42 أو 44. INT هي إما 4 بايت لدينا (اعتمادًا على المترجم). هذا يضع الرقم إما 16+16+2 = 34 أو 32+16+2 = 50 - على افتراض أنه معبأ حقًا.

كما أقول ، إن معرفة أدواتك جزء من مشكلتك.

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

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

بينما أستخدم Linux ، لقد وجدت ذلك بواسطة echo 3 > /proc/cpu/alignment سوف تصدرني بتحذير ، ويصلح قضية المحاذاة. هذا عمل حوله ، لكنه مفيد للغاية في تحديد مكان أن تكون الهياكل غير متوازنة.

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