هل هناك أي النفقات العامة لاستخدام صفائف متغيرة الطول؟

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

  •  19-09-2019
  •  | 
  •  

سؤال

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

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

المحلول

VLA لديه بعض النفقات العامة (مقارنة ب "العادي" المسماة مجموعة من مجموعة تجميع الزمنية).

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

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

نظرا لأن حجم VLA هو قيمة عدد صحيح وقت التشغيل، يمكن تمريرها، بالطبع، كوسيطة سطر الأوامر. VLA لا يهتم حيث يأتي حجمها من.

تم إدخال VLA كصفائف مدفوعة الحجم مع تكلفة منخفضة تخصيص / إلغاء تخصيص. أنها تتناسب بين صفيفات "العادية" المسماة المعالجة المسماة (التي لديها تكلفة تخصيص مخصصات صفر تقريبا، ولكن الحجم الثابت) و mallocالمصفوفات (التي تحتوي على حجم وقت التشغيل، ولكن تكلفة تخصيص تخصيص عالية نسبيا).

VLA OBEY [تقريبا] نفس قواعد الحياة التي تعتمد على النطاق باعتبارها كائنات تلقائية (IE المحلية)، مما يعني أنه في حالة عامة لا يمكنهم استبدالها mallocالمصفوفات. تقتصر إمكانية تطبيقها على المواقف عندما تحتاج إلى مجموعة كبيرة من حجم التشغيل السريع مع عمر أوتوماتيكي نموذجي.

نصائح أخرى

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

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

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

بالإضافة إلى ذلك، مع صفائف متعددة الأبعاد، بقدر ما أعلم يتصرف أكثر مثل Fortran - يمكنك تكوين جميع الأبعاد بشكل حيوي، بدلا من أن تكون عالقا بأحجام ثابتة للجميع ولكن البعد الرائد للمجموعة.


دليل ملموس على بعض النفقات العامة وقت التشغيل ل VLA - على الأقل مع دول مجلس التعاون الخليجي 4.4.2 على SPARC (Solaris 10).

النظر في الملفين أدناه:

VLA.C - باستخدام صفيف طول متغير

#include <assert.h>
#include <stddef.h>
extern size_t identity_matrix(int n, int m);

size_t identity_matrix(int n, int m)
{
    int vla[n][m];
    int i, j;
    assert(n > 0 && n <= 32);
    assert(m > 0 && m <= 32);
    for (i = 0; i < n; i++)
    {
        for (j = 0; j < m; j++)
        {
            vla[i][j] = 0;
        }
        vla[i][i] = 1;
    }
    return(sizeof(vla));
}

FLA.C - باستخدام صفيف طول الثابت

#include <assert.h>
#include <stddef.h>
extern size_t identity_matrix(int n, int m);

size_t identity_matrix(int n, int m)
{
    int fla[32][32];
    int i, j;
    assert(n > 0 && n <= 32);
    assert(m > 0 && m <= 32);
    for (i = 0; i < n; i++)
    {
        for (j = 0; j < m; j++)
        {
            fla[i][j] = 0;
        }
        fla[i][i] = 1;
    }
    return(sizeof(fla));
}

تجميع وأحجام ملفات الكائنات

لأغراض المقارنة، تكون أسماء الصفيف المحلي مختلفة (vla ضد fla)، والأبعاد الموجودة على الصفيف مختلفة عندما يتم الإعلان عنها - وإلا، فإن الملفات هي نفسها.

جمعت باستخدام:

$ gcc -O2 -c -std=c99 fla.c vla.c

أحجام ملفات الكائنات مختلفة إلى حد ما - كما تقاس "LS" و "الحجم":

$ ls -l fla.o vla.o
-rw-r--r--   1 jleffler rd          1036 Jan  9 12:13 fla.o
-rw-r--r--   1 jleffler rd          1176 Jan  9 12:13 vla.o
$ size fla.o vla.o
fla.o: 530 + 0 + 0 = 530
vla.o: 670 + 0 + 0 = 670

لم أكن قد قمت باختبار واسع النطاق لمعرفة مقدار العلامة العامة ثابتة ومقدار المتغير، ولكن هناك النفقات العامة في استخدام VLA.

أنا فقط أتساءل عما إذا كان هناك بعض النفقات العامة لاستخدام صفائف طول المتغير؟

لا

هل يمكن تمرير حجم الصفيف عبر وسيطة سطر الأوامر في وقت التشغيل؟

نعم.

لماذا تم تقديمها، مقارنة مع مجموعة تلقائية وتخصيص ديناميكيا؟

تخصيص تلقائي يسمح فقط بحجم ثابت معروف في وقت الترجمة.

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

يعمل VLA عن طريق وضع مجموعة في كومة. وبعد هذا يجعل التخصيص والوصول بسرعة كبيرة، لكن عادة ما تكون المكدس صغيرا (من بضعة كيلوبايت)، وعندما يفسد VLA المكدس، لا يمكن تمييزه عن العودية اللانهائية.

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

يمكنك تمرير حجم صفيف عبر وسيطة سطر الأوامر، ولكن عليك كتابة التعليمات البرمجية لمعالجة ذلك بنفسك.

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