سؤال

أنا أعمل في مشروع على 8051 حيث يهم كل بايت. على هذا النحو، أنا أستخدم بعض المتغيرات العالمية حيث أنا عادة لن. تضيف الطريقة العادية لمرور المؤشرات في دالة أكثر من اللازم هنا.

لدي عدد من الوظائف التي تستخدم متغيرات بت واحدة (ملحق محمول معين جيم) أن يشير إلى نتيجة وظيفة بالإضافة إلى قيمة الإرجاع العادي.

bit global_error_flag = 0;
bit global_data_ready_flag = 0;

unsigned char A_Function (void) {
    // Do some stuff

    if ( badness ) {
        global_error_flag = 0;
        global_data_ready_flag = 1;

        return 0;
    }

    if ( data_is_ready_use ) {
        global_data_ready_flag = 1;
    }

    return a_value;    
}

void Other_Function (void) {
    unsigned char c;

    c = A_Function();

    if( global_error_flag) {
        // Do error stuff here.
    }
    else
    if( global_data_ready_flag ) {
        // Do data processing here.
    }
    global_error_flag = 0;
    global_data_ready_flag = 0;

}

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

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

#define FUNCTION_SETS_FLAGS(code) (code)

FUNCTION_SETS_FLAGS( c = A_Function() );

أي أفكار أخرى؟

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

المحلول

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

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

كنت أتمسك باتفاقية تسمية للوظائف - وليس بالضرورة المجرية، ولكن شيء مثل A_Function_Returns_Flags, ، أو أقل سرعة إذا كنت تستطيع التفكير في ذلك.

نصائح أخرى

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

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

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

إذا كنت تريد فقط أن تذكر أن الوظيفة تؤثر على المتغير العالمي (ق)، فإن البادئة البسيطة (الهنغارية) قد تساعد.

ولكن إذا كنت تريد أن تذكر كل علم (ملامح) أنه يؤثر، فمن المحتمل أن يكون استخدام رأس الوظيفة هو الطريق للذهاب. مثلا،

  /*************************************************************************
     * FUNCTION    : <function_name>
     * DESCRIPTION : <function description> 
     * PARAMETERS  : 
     *  Param1  - <Parameter-1 explanation>
     *  Param2  - <Parameter-2 explanation>
     *  Param3  - <Parameter-3 explanation>
     * RETURN      : <Return value and type>
     * GLOBAL VARIABLES USED: 
     *  Global1 - <Global-1 explanation>
     *  Global2 - <Global-2 explanation>
     *  Global3 - <Global-3 explanation> 
  *************************************************************************/

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

يمكنك استخدام ماكرو لمحاكاة الوظيفة للحصول على مزيد من المعلمات:


unsigned char _a_function(void);

#define A_Function(ret_val) (*(ret_val) = _a_function(), !global_error_flag)

...
unsigned char var;
/* call the function */
if (!A_Function(&var))
{
    /* error! */
}
else
{
    /* use var */
    var++;
}

لم أحاول تجميعها، لذلك لا أستطيع أن أقول إن هذا سيعمل، لكنني أعتقد أنه ينبغي.

أولا، سأحاول إيصاله بطريقة ما أن هناك منتج واحد فقط واستخدام مستهلك واحد فقط لكل من تلك الأعلام. ثم أقوم بإزالة / تعيين العلم فقط عند الحاجة. أما بالنسبة للإشارة إلى التأثير الجانبي، يجب أن يكون رأس قياسي أعلى وظيفة، Doxygen Style، كافية:

    // Function func
    // Does something
    // Consumes ready_flag and  sets error_flag on error.

    int func()
    {
        if (ready_flag)
        {
            //do something then clear the flag
            if (some_error)
                error_flag = x;
            ready_flag = 0;
        }
        //don't mess with the flags outside of their 'scope'
        return 0;
    }

من ناحية أخرى، إذا كانت الخطأ والأعلام الجاهزة حصرية بشكل متبادل، فيمكنك استخدام البايت (أو بت داخل البايت / التسجيل) للإشارة إلى الاستعداد أو حالة خطأ.

0 للحصول على خطأ، 1 لعدم جاهز / خالية من الأخطاء و 2 جاهز / خالية من الأخطاء (أو -1، 0، 1، أيا كان)

IIRC، لا تعمل مجموعة التعليمات 8051 القياسية على أجزاء واحدة، لذلك استخدام البايت بالكامل ل (مختلف) يجب أن لا تعطيك أي أداء ضخمة.

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

إذا كان عليك حقا التمسك بهذه المتغيرات العالمية، فيمكنك أن تجعل من الواضح أن الوظيفة قد تعدلها من خلال توقع المراجع إليهم كوسائط لوظيفة:

unsigned char A_Function (bit *p_error_flag, bit *p_data_ready_flag)
{
  ...
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top