وظائف افتراضية في ميكروكنترولر - الجانب المظلم

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

كنت أرغب في إنشاء خادم telnet للتحكم في المعدات المختلفة على وحدة WIZnet W5500 الشائعة وغير مكلفة. كل ما هو مطلوب لهذا جزء من مكتبة Arduino القياسية ، والنتيجة يمكن العثور عليها هنا . ولكن هذا ليس عنه. أول ما فاجأني حقًا هو أن هذا الرمز الوظيفي البسيط احتل أكثر من نصف فلاش ATmega328P. بالطبع ، هناك الكثير من التعليمات البرمجية في مكتبة الإيثرنت ، ولكن ليس كل ذلك يُستخدم ، يجب على المحول البرمجي التخلص من التعليمات البرمجية غير المستخدمة من البرامج الثابتة المجمعة. تحقق مما إذا كان هذا هو الحال.

نذهب إلى الدليل حيث يتم التجميع - يمكن رؤية المسار إليه في رسائل الترجمة ، ونفعل objdump -t <ملف البرنامج الثابت> للحصول على جدول الأحرف. نرى فيه الكثير من الوظائف المرتبطة بشبكة Ethernet ، بما في ذلك الوظائف التي لا تكون حاجتها واضحة ، على سبيل المثال ، وظائف العمل مع UDP. بمعنى أنه يبدو أن إزالة الوظائف غير الضرورية لم يحدث. ما هو الموضوع؟

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

نتحقق من صحة فرضيتنا. خذ مكتبة Ethernet من github ، على سبيل المثال هنا ، حتى لا تلمس المعيار ، وقم بتعديلها. نزيل الميراث ، ونقوم بعمل وظائف افتراضية ببساطة عن طريق الأساليب. كيفية القيام بذلك بعناية ، بطريقة قابلة للعكس ، يمكنك أن ترى هنا . النتيجة: انخفض حجم الرمز بمقدار 4460 بايت - أكثر من ربع الحجم الأصلي.

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

Source: https://habr.com/ru/post/ar483862/


All Articles