متى يجب علي استخدام تجريد الكتابة في الأنظمة المدمجة

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

  •  08-06-2019
  •  | 
  •  

سؤال

لقد عملت على عدد من الأنظمة المدمجة المختلفة.لقد استخدموا جميعا typedefس (أو #defines) لأنواع مثل UINT32.

هذه تقنية جيدة لأنها تنقل حجم النوع إلى المبرمج وتجعلك أكثر وعيًا بفرص التجاوز وما إلى ذلك.

لكن في بعض الأنظمة، تعلم أن المترجم والمعالج لن يتغيرا طوال عمر المشروع.

إذًا ما الذي يجب أن يؤثر على قرارك بإنشاء وتنفيذ أنواع خاصة بالمشروع؟

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

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

بالنسبة لكل شيء آخر، فإن الأنواع لها أهمية أقل.
يجب أن تكون حريصًا على عدم التسبب في تجاوز السعة وقد تحتاج إلى الانتباه لاستخدام التسجيل والمكدس.والتي قد تقودك إلى UINT16, UCHAR.باستخدام أنواع مثل UCHAR ومع ذلك، يمكن إضافة "زغب" المترجم.نظرًا لأن السجلات عادةً ما تكون أكبر، فقد يضيف بعض المترجمين تعليمات برمجية لإجبار النتيجة على الكتابة.

i++;
يمكن أن تصبح
ADD REG,1
AND REG, 0xFF
وهو أمر غير ضروري.

لذلك أعتقد أن سؤالي كان ينبغي أن يكون:-

نظرًا للقيود التي تفرضها البرامج المضمنة، ما هي أفضل سياسة يمكن وضعها لمشروع يعمل عليه العديد من الأشخاص - وليس جميعهم على نفس المستوى من الخبرة.

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

المحلول

أستخدم تجريد النوع نادرًا جدًا.فيما يلي حججي، مرتبة حسب الترتيب الذاتي:

  1. تختلف المتغيرات المحلية عن أعضاء البنية والمصفوفات بمعنى أنك تريد احتواؤها في السجل.على هدف 32ب/64ب، محلي int16_t يمكن أن يجعل التعليمات البرمجية أبطأ مقارنة بـ int المحلي حيث سيتعين على المترجم إضافة عمليات إلى /force/ overflow وفقًا لدلالات int16_t.بينما يحدد C99 intfast_t typedef، AFAIK سوف يتناسب int العادي مع السجل أيضًا، ومن المؤكد أنه اسم أقصر.

  2. المنظمات التي تحب هذه الأنماط تنتهي دائمًا بالعديد منها (INT32, int32_t, INT32_T, ، لا نهاية).وبالتالي، فإن المؤسسات التي تستخدم الأنواع المضمنة تكون أفضل حالًا، بطريقة ما، من خلال مجموعة واحدة فقط من الأسماء.أتمنى أن يستخدم الأشخاص typedefs من stdint.h أو windows.h أو أي شيء موجود؛وعندما لا يكون لدى الهدف ملف ‎.h، ما مدى صعوبة إضافة ملف؟

  3. من الناحية النظرية، يمكن أن تساعد المحارف في قابلية النقل، لكنني شخصيًا لم أحصل على أي شيء منها أبدًا.هل هناك نظام مفيد يمكنك الانتقال من هدف 32b إلى هدف 16b؟هل يوجد نظام 16ب ليس من السهل نقله إلى هدف 32ب؟علاوة على ذلك، إذا كانت معظم vars عبارة عن ints، فستحصل في الواقع على شيء من 32 بت في الهدف الجديد، ولكن إذا كانت كذلك int16_t, لن تفعل ذلك.والأماكن التي يصعب نقلها تتطلب فحصًا يدويًا على أي حال؛قبل أن تجرب المنفذ، فإنك لا تعرف مكانه.الآن، إذا اعتقد شخص ما أنه من السهل جدًا نقل الأشياء إذا كان لديك رموز كتابة في كل مكان - عندما يحين وقت النقل، وهو ما يحدث لعدد قليل من الأنظمة، فاكتب برنامجًا نصيًا يحول جميع الأسماء في قاعدة التعليمات البرمجية.يجب أن يعمل هذا وفقًا لمنطق "لا يلزم إجراء فحص يدوي"، وهو يؤجل الجهد إلى النقطة الزمنية التي يحقق فيها فائدة فعلية.

  4. الآن، إذا كانت قابلية النقل هي فائدة نظرية لرموز الكتابة، مقروئية بالتأكيد يذهب هباء.مجرد إلقاء نظرة على stdint.h: {int,uint}{max,fast,least}{8,16,32,64}_t.الكثير من الأنواع.يحتوي البرنامج على الكثير من المتغيرات.هل هو حقا من السهل أن نفهم ما يجب أن يكون int_fast16_t والتي يجب أن تكون uint_least32_t؟كم مرة نقوم بالتحويل بينهما بصمت، مما يجعلها عديمة الفائدة تمامًا؟(أنا أحب بشكل خاص تحويلات BOOL/Bool/eBool/boolean/bool/int.كل برنامج تكتبه منظمة منظمة تفرض الكتابة المكتوبة مليء بذلك).

  5. بالطبع في C++، يمكننا أن نجعل نظام الكتابة أكثر صرامة، عن طريق تغليف الأرقام في عمليات إنشاء فئة القالب مع عوامل تشغيل وأشياء مثقلة.هذا يعني أنك ستتلقى الآن رسائل خطأ بالنموذج "رقم الفئة<int,Least,32> لا يحتوي على عامل تشغيل+ حمل زائد لوسيطة النوع رقم الفئة<unsigned long long,Fast,64>، المرشحون هم..." لا تسمي هذا "سهولة القراءة" أيضًا.فرصك في تنفيذ هذه الفئات المجمعة بشكل صحيح هي فرص مجهرية، وفي معظم الأوقات ستنتظر حتى يتم تجميع عدد لا يحصى من عمليات إنشاء القوالب.

نصائح أخرى

يحتوي معيار C99 على عدد من أنواع الأعداد الصحيحة ذات الحجم القياسي.إذا كان بإمكانك استخدام مترجم يدعم C99 (يدعمه دول مجلس التعاون الخليجي)، فستجد ذلك في <stdint.h> ويمكنك فقط استخدامها في مشاريعك.

أيضًا، قد يكون من المهم بشكل خاص في المشاريع المضمنة استخدام الأنواع كنوع من "شبكة الأمان" لأشياء مثل تحويلات الوحدات.إذا كان بإمكانك استخدام C++، فأنا أفهم أن هناك بعض مكتبات "الوحدات" التي تتيح لك العمل في الوحدات المادية التي تم تحديدها بواسطة نظام نوع C++ (عبر القوالب) التي يتم تجميعها كعمليات على الأنواع العددية الأساسية.على سبيل المثال، لن تسمح لك هذه المكتبات بإضافة ملف distance_t إلى أ mass_t لأن الوحدات لا يصطف؛سوف تحصل في الواقع على خطأ مترجم.

حتى لو لم تتمكن من العمل بلغة C++ أو لغة أخرى تتيح لك كتابة التعليمات البرمجية بهذه الطريقة، يمكنك على الأقل استخدام نظام النوع C لمساعدتك في اكتشاف أخطاء مثل تلك عن طريق العين.(كان هذا في الواقع هو القصد الأصلي من تدوين Simonyi الهنغاري.) فقط لأن المترجم لن يصرخ عليك لإضافة meter_t إلى أ gram_t لا يعني أنه لا يجب عليك استخدام أنواع من هذا القبيل.ستكون مراجعات التعليمات البرمجية أكثر إنتاجية في اكتشاف أخطاء الوحدة بعد ذلك.

رأيي هو إذا كنت تعتمد على الحد الأدنى/الحد الأقصى/الحجم المحدد لا فقط افترض أن (قل) ل unsigned int هو 32 بايت - الاستخدام uint32_t بدلاً من ذلك (على افتراض أن المترجم الخاص بك يدعم C99).

أحب استخدام أنواع stdint.h لتحديد واجهات برمجة تطبيقات النظام على وجه التحديد لأنها توضح بوضوح حجم العناصر الكبيرة.بالعودة إلى الأيام القديمة لنظام التشغيل Palm OS، تم تعريف واجهات برمجة تطبيقات النظام باستخدام مجموعة من الأنواع غير المرغوب فيها مثل "Word" و"SWord" الموروثة من نظام التشغيل Mac OS الكلاسيكي للغاية.لقد أجروا عملية تنظيف ليقولوا بدلاً من ذلك Int16، مما جعل واجهة برمجة التطبيقات (API) أسهل للوافدين الجدد للفهم، خاصة مع مشكلات مؤشر 16 بت الغريبة على هذا النظام.عندما كانوا يصممون نظام التشغيل Palm OS Cobalt، قاموا بتغيير تلك الأسماء مرة أخرى لتتناسب مع أسماء stdint.h، مما جعل الأمر أكثر وضوحًا وقلل من كمية أنماط الكتابة التي كان عليهم إدارتها.

أعتقد أن معايير MISRA تقترح (تتطلب؟) استخدام typedefs.

من وجهة نظر شخصية، فإن استخدام typedefs لا يترك أي ارتباك فيما يتعلق بالحجم (بالبت/البايت) لأنواع معينة.لقد رأيت مطورين رئيسيين يحاولون كلا الطريقتين للتطوير باستخدام الأنواع القياسية، على سبيل المثال.int واستخدام الأنواع المخصصة على سبيل المثال.UINT32.

إذا لم يكن الرمز محمولاً، فهناك القليل حقيقي الاستفادة من استخدام typedefs، لكن ، إذا كنت مثلي تعمل على كلا النوعين من البرامج (البيئة المحمولة والثابتة)، فقد يكون من المفيد الاحتفاظ بمعيار واستخدام الأنواع المقطوعة.على الأقل كما تقول، يكون المبرمج على دراية تامة بحجم الذاكرة التي يستخدمها.هناك عامل آخر يجب مراعاته وهو ما مدى "تأكدك" من عدم نقل الكود إلى بيئة أخرى؟لقد رأيت كودًا خاصًا بالمعالج يجب ترجمته حيث اضطر مهندس الأجهزة فجأة إلى تغيير اللوحة، وهذا ليس وضعًا جيدًا ولكن نظرًا لتعريفات الكتابة المخصصة، كان من الممكن أن يكون الأمر أسوأ بكثير!

الاتساق والراحة وسهولة القراءة.يعد "UINT32" أكثر قابلية للقراءة والكتابة من "unsigned long long"، وهو ما يعادل بعض الأنظمة.

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

إذا كانت أنظمتك المدمجة بطريقة أو بأخرى نظام السلامة الحرجة (أو ما شابه ذلك) بقوة ينصح (إذا لم يكن ذلك مطلوبًا) لاستخدام typedefs على الأنواع العادية.

مثل المعارف التقليدية. وقد قال من قبل، ميسرا-C لديه قاعدة (استشارية) للقيام بذلك:

القاعدة 6.3 (الاستشارية): يجب استخدام typedefs التي تشير إلى الحجم والتوقيع بدلاً من الأنواع الرقمية الأساسية.

(من MISRA-C 2004؛إنها القاعدة رقم 13 (مقدم) من MISRA-C 1998)


وينطبق الشيء نفسه أيضًا على لغة C++ في هذا المجال؛على سبيل المثال. معايير الترميز JSF C++:

AV القاعدة 209 سيتم إنشاء ملف UniversalTypes لتحديد جميع أنواع sta ndard للمطورين لاستخدامها.وتشمل الأنواع:[uint16، int16، uint32_t الخ.]

استخدام <stdint.h> يجعل التعليمات البرمجية الخاصة بك أكثر سهولة في اختبار الوحدة على جهاز الكمبيوتر.

يمكن أن يعضك بشدة عندما يكون لديك اختبارات لكل شيء ولكنه لا يزال يكسر نظامك المستهدف بسبب int فجأة أصبح طوله 16 بت فقط.

ربما أكون غريبًا، لكني أستخدم ub وui وul وsb وsi وsl لأنواع الأعداد الصحيحة الخاصة بي.ربما يبدو حرف "i" لـ 16 بت قديمًا بعض الشيء، لكني أحب مظهر ui/si أفضل من uw/sw.

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