كيف يمكنك أن تفعل C ++ عندما لا يحتوي برنامج التحويل البرمجي المضمن على دعم جديد أو STL؟

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

سؤال

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

لا يدعم المحول البرمجي الذي لدينا للحصول على ميكروكماني Atmel 8 بت لدينا المشغلين الجدد أو الحذف، ولا يدعمون STL C ++. يمكنني برمجةها في C، لكن علي تنفيذ خوارزمية * التي لم أفعلها من قبل. بينما حاولت C في البداية، سرعان ما أدركت أنني لم أفعل أبدا من قبل. إن محاولة تكوين الكائنات مع الهياكل والوظائف تبطئني منذ أن كنت معتادا على بناء جملة C ++ أكثر منظفا.

بغض النظر، يمكن العثور على الصياغة الدقيقة لأوجه القصور الخاصة بي للمجمعات المجمعين هنا: http://www.nongnu.org/avr-libc/user-manual/faq.html#faq_cplusplus.

للتغلب عليها وما زالت تستخدم C ++ لقد نظرت في الاحتمالات التالية. 1) لا تخصيص أي شيء، ما عليك سوى استخدام القوالب لإنشاء صفيف ثابتة على المكدس. 2) تخصيص وإيجاد بعض الاختراق لاستدعاء المنشئ للكائنات بمجرد تخصيص المساحة لهم. التنسيب الجديد ليس خيارا لأن الجديد ليس مشغلا. 3) استخدم فقط C وامتصاصه، وهو متحكم هو لماذا أحصل على خيالي؟ 4) ابحث عن مترجم أفضل من المحتمل أن يكلف $$$.

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

هذا يبدو فظيعا ولا أعرف ما إذا كان قد يعمل بشكل موثوق، لكنني أفكر في ذلك. أعرف أن vtables يمكن أن تكون مشكلة، لكنني لا أنوي وجود أي vtables لأنها مجرد ميكروكماني 8 بت.

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

المحلول

فقط للتسجيل، لن يؤثر الزربيرية على البتات في كائن ما إذا كان المدمر يسمى (ما لم يكن لدى المحول البرمجي Quirk خاص تمكن هذا السلوك). فقط اكتب بعض بيانات التسجيل في Destructor الخاص بك لاختبار ذلك.

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


ومع ذلك، إذا كان يجب عليك، فلا يزال بإمكانك استخدام التنسيب الجديد. إذا لم يكن لديك <new> رأس، إليك الخطوط ذات الصلة مباشرة منها على إصدار GCC:

// Default placement versions of operator new.
inline void* operator new(std::size_t, void* __p) throw() { return __p; }
inline void* operator new[](std::size_t, void* __p) throw() { return __p; }

// Default placement versions of operator delete.
inline void  operator delete  (void*, void*) throw() { }
inline void  operator delete[](void*, void*) throw() { }

عصا أنه في مكان ما في ملف رأس مضمن من خلال كل ملف مصدر يستخدم وضع جديد / حذف.

ملف عينة يختبر هذا:

#include <cstdio>
#include <new>

int
main(int argc, char** argv)
{
    typedef char const* cstr;
    char foobar[16];
    cstr* str = new (&foobar) cstr(argc > 1 ? argv[1] : "Hello, world!");
    std::puts(*str);
    str->~cstr();
}

على بلدي من دول مجلس التعاون الخليجي، هذا لا يستخدم libstdc++ على الإطلاق (إذا -fno-exceptions يستخدم).


الآن، إذا كنت ترغب في الجمع بين ذلك مع malloc (إذا توفر النظام الأساسي الخاص بك هذا)، فيمكنك القيام بذلك:

#include <cstdio>
#include <cstdlib>

inline void* operator new  (std::size_t n) {return std::malloc(n);}
inline void* operator new[](std::size_t n) {return std::malloc(n);}
inline void  operator delete  (void* p) {std::free(p);}
inline void  operator delete[](void* p) {std::free(p);}

int
main(int argc, char** argv)
{
    typedef char const* cstr;
    cstr* str = new cstr(argc > 1 ? argv[1] : "Hello, world!");
    std::puts(*str);
    delete str;
}

هذا يسمح لك باستخدام المعيار new/delete أن تكون على دراية، دون الحاجة إلى استخدام libstdc++.

حظ سعيد!

نصائح أخرى

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

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

أعتقد أنك تقترب من مشكلة وجهة نظر أقل من الأمثل.

أنت تركز على التحويل البرمجي (أو عدم وجوده) بدلا من التركيز على الأجهزة.

الإجابة الأكثر احتمالا على أسئلتك الرئيسية هي "لأن الأجهزة لا تدعم كل ما هي الأشياء C ++". تتم الإشارة إلى الأجهزة المضمنة (الحوكم) لتخصيص تصميم الأجهزة - خرائط الذاكرة، ومعالجات المقاطعة، I / O، إلخ.

في رأيي، يجب عليك أولا قضاء بعض الوقت مع كتاب الأجهزة للحصول على ميكروكنترولر، وتعلم ISS و Outs of the Device - أي كيف تم تصميمه ولأي غرض أساسي. تم تصميم بعضها للتلاعب بالذاكرة السريعة، والبعض الآخر من أجل التعامل مع I / O بسرعة، وبعض أعمال نوع A / D، وبعضها لمعالجة الإشارات. يملي نوع ميكروكنترولر تعليمات المجمع التي كتبوها لذلك، والتي تملي ما يمكن أن يفعله أي مبرر أعلى مستوى فعالا.

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

بشكل عام، لا تدعم MicroConTrollers C ++ لأن التصميم لا يهتم حقا بالكائنات، أو معالجة الذاكرة الفاخرة (من منظور C ++). يمكن القيام به، لكنك غالبا ما تحاول جنيد ربط دائري في حفرة مربعة للحصول على منشئين ومدمرين (و "جديد" و "حذف") للعمل في بيئة مايكرو.

إذا كان لديك مترجم C لهذه الوحدة، فاعتبره نعمة. غالبا ما يكون برنامج التحويل البرمجي C جيدا "أكثر من كافية" لإنشاء برنامج مضمن ممتاز.

هتافات،

-Richard.

فقط لأنه لا يعني أن هذه الأدوات لا تعني أنه لا يمكنك الاستفادة من C ++. إذا كان المشروع كبيرا بما فيه الكفاية، فقد يكون الوصول إلى التصميم الموجه نحو الكائن وحده التحفيز بما فيه الكفاية.

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

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

كان لدي مترجم مماثل ينفذ نسخة غريبة من Embedded-C ++ القياسية. وبعد كان لدينا operator new والتي من شأنها أن تسمي منشئين بالنسبة لنا والمدمرين في معظم الحالات. وبعد ذهب البائع المترجم / وقت التشغيل وتنفيذ try و catch استخدام setjmp و longjmp ك الراحة إلى المهندس. وبعد كانت المشكلة أنهم لم يذكروا أن أ throw لن يسبب استدعاء المدمرين للأشياء المحلية!

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

قد تجد بعض رمز مفيد على بلدي موقع * البرنامج التعليمي. وبعد على الرغم من أن الشفرة كتبت لدعم هذا الاستخدامات STL يجب أن يكون من السهل تجريد دعم STL. بالإضافة إلى ذلك، هناك مصلح حمام السباحة المضمن معه (FSA.H) الذي كتبته لتسريع STL على لوحات المفاتيح. إنه رمز C ++، لكنني أقوم بتنفيذها في الأصل من ج ولا أعتقد أنه سيكون من الصعب القيام بذلك في الاتجاه الآخر. يتم اختبار التعليمات البرمجية من قبل أكثر من 10000 شخص، لذلك فهو قاعدة جيدة للبدء منه.

استبدال هياكل STL التي أستخدمها ليست مشكلة لأنها تقتصر على ناقصها. يمكنني استخدام أحد المتجهات كقائمة انتظار ذات أولوية باستخدام وظائف الكومة (make_heap و push_heap). يمكنك استبدال ذلك مع بلدي كود C القديم التي لديها قائمة انتظار أولوية تنفذ في C التي يجب أن تسقط فقط في التعليمات البرمجية الخاصة بك. (الذي يقوم به فقط ALLOC، حتى تتمكن من استبدال ذلك بمؤشر إلى منطقة محفوظة من ذاكرتك.

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

void PQueueInitialise( PQUEUE *pq, int32 MaxElements, uint32 MaxRating, bool32 bIsAscending );
void PQueueFree( PQUEUE *pq );
int8 PQueuePush( PQUEUE *pq, void *item,  uint32 (*PGetRating) ( void * ) );
int32 PQueueIsFull( PQUEUE *pq );
int32 PQueueIsEmpty( PQUEUE *pq );
void *PQueuePop( PQUEUE *pq, uint32 (*PGetRating) ( void * ) );

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

عند القيام بعمل مضمن، لم أتمكن من ربط وقت التشغيل C لقيود الذاكرة، لكن الأجهزة لديها تعليمات DMA (مخصصات الذاكرة الديناميكية) لذلك كتبت MOLOC الخاصة بي مع تلك الأجهزة، والأجهزة التي يحتمل أن يكون لها ميزة مماثلة، لذلك يمكنك كتابة malloc ثم جديد بناء على malloc.

على أي حال في النهاية، استخدمت مخصصات المكدس 99٪، وبعض الحدود تضع كائنات ثابتة OS التي أعديتها، عن طريق التشويش في المكان. هذا قد لي حلا جيدا.

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