va_list
الدوال متغيّرة المعاملات va_list
stdarg.h تتيح كتابة دوال تقبل عددًا متغيّرًا من المعاملات، بنفس الفكرة التي تُبنى عليها printf وscanf.
دالة متغيّرة المعاملات تُعرَّف بمعامل ثابت واحد على الأقل يليه ...، ثم تستخدم ثلاثة ماكروهات من stdarg.h: va_start لتهيئة قائمة المعاملات (تحتاج آخر معامل ثابت كمرجع)، va_arg لسحب المعامل التالي مع تحديد نوعه صراحة في كل استدعاء، وva_end لإنهاء القراءة وتحرير أي حالة داخلية.
لا توجد طريقة تلقائية لمعرفة عدد المعاملات الممرَّرة فعليًا أو أنواعها من داخل الدالة نفسها — لهذا printf تعتمد على تحليل نص التنسيق (%d، %s...) لمعرفة كم معاملًا تقرأ ومن أي نوع. يجب أن يتطابق نوع va_arg تمامًا مع نوع المعامل الفعلي الممرَّر، وإلا فالسلوك غير معرّف.
الصياغة
ReturnType func(FixedType fixed, ...); va_list args; va_start(args, fixed); Type val = va_arg(args, Type); va_end(args);
📄 مثال
#include <stdarg.h>
#include <stdio.h>
int sum(int count, ...) {
va_list args;
va_start(args, count);
int total = 0;
for (int i = 0; i < count; i++) {
total += va_arg(args, int);
}
va_end(args);
return total;
}
printf("%d\n", sum(3, 10, 20, 30)); // 60أهم النقاط
| العنصر | الوظيفة |
|---|---|
| va_list | نوع يخزّن حالة قراءة المعاملات المتغيّرة |
| va_start(list, last_fixed) | يهيّئ القائمة، ويحتاج اسم آخر معامل ثابت قبل ... |
| va_arg(list, Type) | يقرأ المعامل التالي على أنه Type وينتقل للذي يليه |
| va_end(list) | إلزامي بعد الانتهاء من القراءة قبل خروج الدالة |
💡 نصائح عملية
- مرّر عدد المعاملات صراحة (مثل count) أو استخدم قيمة حارسة (sentinel) لمعرفة متى تتوقف القراءة
- تأكد أن نوع va_arg يطابق تمامًا نوع القيمة الممرَّرة فعليًا وقت الاستدعاء
⚠️ أخطاء شائعة
- نسيان استدعاء va_end بعد va_start
- قراءة نوع مختلف عن النوع الفعلي الممرَّر عبر va_arg — سلوك غير معرّف وقد يسبب تعطّلًا
خصائص ذات صلة
🎓 تريد فهم الصورة الكاملة خطوة بخطوة؟ ابدأ من مسار C الكامل بالعربي.