stdarg(3)

الاسم
stdarg, va_start, va_arg, va_end, va_copy - قوائم المعاملات المتغيرة

المكتبة
مكتبة سي المعيارية (libc، -lc)

موجز
#include <stdarg.h>

void va_start(va_list ap, last);
type va_arg(va_list ap, type);
void va_end(va_list ap);
void va_copy(va_list dest, va_list src);

الوصف
قد تُستدعى دالة بعدد متغير من المعاملات من أنواع متغيرة. يُصرح ملف التضمين <stdarg.h> بنوع va_list ويُعرف ثلاث وحدات ماكرو للتنقل عبر قائمة من المعاملات التي لا يُعرف عددها وأنواعها للدالة المُستدعاة.

يجب على الدالة المُستدعاة أن تُصرح بكائن من النوع va_list الذي تستخدمه وحدات الماكرو va_start() و va_arg() و va_end().

  va_start()
وحدة الماكرو va_start() تُهيئ ap للاستخدام اللاحق بواسطة va_arg() و va_end()، ويجب استدعاؤها أولاً.

المعامل last هو اسم آخر معامل قبل قائمة المعاملات المتغيرة، أي آخر معامل تعرف الدالة المُستدعية نوعه.

لأن عنوان هذا المعامل قد يُستخدم في وحدة الماكرو va_start()، فلا ينبغي التصريح عنه كمتغير سجل، أو كنوع دالة أو مصفوفة.

  va_arg()
وحدة الماكرو va_arg() تتوسع إلى تعبير له نوع وقيمة المعامل التالي في الاستدعاء. المعامل ap هو va_list ap المُهيأ بواسطة va_start(). كل استدعاء لـ va_arg() يُعدل ap بحيث يُرجع الاستدعاء التالي المعامل التالي. المعامل type هو اسم نوع مُحدد بحيث يمكن الحصول على نوع مؤشر لكائن له النوع المُحدد ببساطة بإضافة * إلى type.

الاستخدام الأول لوحدة الماكرو va_arg() بعد استخدام وحدة الماكرو va_start() يُرجع المعامل بعد last. الاستدعاءات المتتالية تُرجع قيم المعاملات المتبقية.

إذا لم يكن هناك معامل تالٍ، أو إذا كان type غير متوافق مع نوع المعامل التالي الفعلي (كما يُرفع وفقًا لترقيات المعاملات المبدئية)، فستحدث أخطاء عشوائية.

إذا مُرر ap إلى دالة تستخدم va_arg(ap,type), فإن قيمة ap تكون غير مُعرفة بعد عودة تلك الدالة.

  va_end()
يجب أن يُقابل كل استدعاء لـ va_start() استدعاء مقابل لـ va_end() في نفس الدالة. بعد الاستدعاء va_end(ap) يكون المتغير ap غير مُعرف. عمليات اجتياز متعددة للقائمة، كل منها محصور بين va_start() و va_end()، ممكنة. قد تكون va_end() وحدة ماكرو أو دالة.

  va_copy()
وحدة الماكرو va_copy() تنسخ قائمة المعاملات المتغيرة (المُهيأة سابقًا) src إلى dest. السلوك كما لو أن va_start() طُبقت على dest بنفس المعامل last، متبوعة بنفس عدد استدعاءات va_arg() التي استُخدمت للوصول إلى الحالة الحالية لـ src.

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

    va_list aq = ap;

لسوء الحظ، هناك أيضًا أنظمة تجعلها مصفوفة من المؤشرات (بطول 1)، وهناك يحتاج المرء

    va_list aq;
    *aq = *ap;

أخيرًا، على الأنظمة التي تُمرر فيها المعاملات في المسجلات، قد يكون من الضروري لـ va_start() تخصيص ذاكرة، وتخزين المعاملات هناك، وأيضًا إشارة إلى أي معامل هو التالي، بحيث يمكن لـ va_arg() التنقل عبر القائمة. الآن يمكن لـ va_end() تحرير الذاكرة المخصصة مرة أخرى. لاستيعاب هذا الموقف، يضيف C99 كلية va_copy()، بحيث يمكن استبدال التعيين أعلاه بـ

    va_list aq;
    va_copy(aq, ap);
    ...
    va_end(aq);

يجب أن يُقابل كل استدعاء لـ va_copy() باستدعاء مقابل لـ va_end() في نفس الدالة. بعض الأنظمة التي لا توفر va_copy() لديها __va_copy بدلاً من ذلك، لأن هذا هو الاسم المستخدم في الاقتراح المسود.

السمات
للاطلاع على شرح للمصطلحات المستخدمة في هذا القسم، انظر attributes(7).
الواجهة | السمة | القيمة
va_start(), va_end(), va_copy() | سلامة الخيوط | MT-Safe
va_arg() | سلامة الخيوط | MT-Safe race:ap

المعايير
C11, POSIX.1-2008.

التاريخ

va_start()
va_arg()
va_end()
    C89, POSIX.1-2001.

va_copy()
    C99، POSIX.1-2001.

تحذيرات
على عكس الكليات التاريخية varargs، لا تسمح كليات stdarg للمبرمجين بترميز دالة بدون معاملات ثابتة. تُولد هذه المشكلة عملًا بشكل رئيسي عند تحويل كود varargs إلى كود stdarg، ولكنها تُنشئ أيضًا صعوبات للدوال المتغيرة التي ترغب في تمرير جميع معاملاتها إلى دالة تأخذ معامل va_list، مثل vfprintf(3).

أمثلة
تأخذ الدالة foo سلسلة محارف من حروف التنسيق وتطبع المعامل المرتبط بكل حرف تنسيق بناءً على النوع.

    #include <stdio.h>
    #include <stdarg.h>

    void
    foo(char *fmt, ...)   /* '...' is C syntax for a variadic function */

    {
        va_list ap;
        int d;
        char c;
        char *s;

        va_start(ap, fmt);
        while (*fmt)
            switch (*fmt++) {
            case 's':              /* string */
                s = va_arg(ap, char *);
                printf("string %s\n", s);
                break;
            case 'd':              /* int */
                d = va_arg(ap, int);
                printf("int %d\n", d);
                break;
            case 'c':              /* char */
                /* need a cast here since va_arg only
                   takes fully promoted types */
                c = (char) va_arg(ap, int);
                printf("char %c\n", c);
                break;
            }
        va_end(ap);
    }

انظر أيضًا
vprintf(3), vscanf(3), vsyslog(3)

ترجمة
تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي <zayed.alsaidi@gmail.com>

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 (https://www.gnu.org/licenses/gpl-3.0.html) أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: kde-l10n-ar@kde.org.