فيجوال - رموز لغة c++




هل هناك أي حمل لإعلان متغير داخل حلقة؟(C++) (9)

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

هذا السؤال لديه بالفعل إجابة هنا:

أنا فقط أتساءل عما إذا كان هناك أي فقدان للسرعة أو الكفاءة إذا فعلت شيئا من هذا القبيل:

int i = 0;
while(i < 100)
{
    int var = 4;
    i++;
}

الذي يعلن int var مائة مرة. يبدو لي أنه سيكون هناك ، لكنني لست متأكدًا. سيكون أكثر عملية / أسرع للقيام بذلك بدلا من ذلك:

int i = 0;
int var;
while(i < 100)
{
    var = 4;
    i++;
}

أم أنها هي نفسها ، وبسرعة ، وبكفاءة؟


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


عادةً ما يتم تخصيص مساحة التكديس للمتغيرات المحلية في نطاق الوظائف. لذلك لا يحدث أي تعديل لمدّة المكدس داخل الحلقة ، ما عليك سوى تعيين 4 إلى var . لذلك هذين القصاصين له نفس مقدار الحمل.


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

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


كلاهما نفس الشيء ، وهنا كيف يمكنك معرفة ذلك ، من خلال النظر في ما يفعله المترجم (حتى بدون تحسين الإعداد إلى مرتفع):

انظر إلى ما يفعله المترجم (gcc 4.0) بالأمثلة البسيطة:

1.C:

main(){ int var; while(int i < 100) { var = 4; } }

gcc -S 1.c

1.S:

_main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $24, %esp
    movl    $0, -16(%ebp)
    jmp L2
L3:
    movl    $4, -12(%ebp)
L2:
    cmpl    $99, -16(%ebp)
    jle L3
    leave
    ret

2.C

main() { while(int i < 100) { int var = 4; } }

gcc -S 2.c

2.S:

_main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $24, %esp
        movl    $0, -16(%ebp)
        jmp     L2
L3:
        movl    $4, -12(%ebp)
L2:
        cmpl    $99, -16(%ebp)
        jle     L3
        leave
        ret

من هذه ، يمكنك رؤية أمرين: أولاً ، الرمز هو نفسه في كليهما.

ثانيًا ، يتم تخصيص التخزين لـ var خارج الحلقة:

         subl    $24, %esp

وأخيرًا ، يكون الشيء الوحيد في الحلقة هو فحص المهمة والحالة:

L3:
        movl    $4, -12(%ebp)
L2:
        cmpl    $99, -16(%ebp)
        jle     L3

وهي عبارة عن كفاءة بقدر ما يمكنك بدون إزالة الحلقة تمامًا.


لأنواع البدائية وأنواع POD ، فإنه لا فرق. سيقوم المحول البرمجي بتخصيص مساحة مكدس للمتغير في بداية الدالة وإلغاء تخصيصها عند إرجاع الدالة في كلتا الحالتين.

بالنسبة للأنواع غير التابعة للطبقة التي تحتوي على أدوات بناء غير تافهة ، فإنها ستحدث فرقًا - في هذه الحالة ، لن يؤدي وضع المتغير خارج الحلقة إلا إلى استدعاء المُنشئ والمدمِّر مرة واحدة ومُعامل التكرار كل مرة ، في حين يتم وضعه داخل حلقة استدعاء منشئ و destructor لكل تكرار للحلقة. واعتمادًا على ما يفعله مُنشئ الطبقة والمدمِّر ومشغل المهمة ، قد يكون هذا الأمر مرغوبًا أو غير مرغوب فيه.


مع متغيرين فقط ، من المحتمل أن يقوم المترجم بتعيين سجل لكليهما. هذه السجلات موجودة على أي حال ، لذلك هذا لا يستغرق وقتا. هناك 2 سجل الكتابة وتسجيل واحد يقرأ التعليمات في كلتا الحالتين.


معظم المترجمين الحديثين سيعملون على تحسين ذلك من أجلك. أن يقال سأستخدم المثال الأول الخاص بك كما أجد أنه أكثر قابلية للقراءة.


#include <stdio.h>
int main()
{
    for(int i = 0; i < 10; i++)
    {
        int test;
        if(i == 0)
            test = 100;
        printf("%d\n", test);
    }
}

يطبع الرمز أعلاه دائمًا 100 10 مرة مما يعني أنه يتم تخصيص المتغير المحلي داخل الحلقة مرة واحدة فقط لكل استدعاء دالة.





variable-declaration