سؤال

لدي هذا البرنامج الذي أريد العمليات الأخرى أن تكون قادرا على استدعاء الوظائف على (من خلال مآخذ UNIX). بروتوكول الرسائل بسيط للغاية، اسم الوظيفة، توقيع وظيفة، ومخزن مؤقت (char *) الذي يحمل المعلمات.

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

لذلك في الأساس، قد تبدو وظيفة:

int somefunc(int someparam, double another)
{
    return 1234;
}

الآن أنا سجل مع المكتبة:

//           func ptr   name       signature
REG_FUNCTION(somefunc, "somefunc", "i:id");

عندما يأتي الطلب، أفعل بعض التحقق من الأخطاء، مرة واحدة صالحة أريد استدعاء الوظيفة. لذلك لدي المتغيرات:

void * funcptr = (the requested function);
char * sig = (the function signature);
char * params = (a buffer of function parameters);
//note that the params buffer can hold data types of arbitrary lengths

كيف يمكنني استدعاء الوظيفة مع المعلمات في ج؟

شكرا!

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

المحلول

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

لا توجد أيضا بشكل عام بشكل عام للتعبير عنها في C أنها تريد استدعاء وظيفة مع مجموعة معينة من الوسائط، وأن قيم الحجج تحتاج إلى تفكيك من المخزن المؤقت لحياء عشوائي.

يمكنك أن تفعل شيئا فظيعا مثل هذا:

enum { VOID_INT, VOID_INT_DOUBLE, VOID_DOUBLE_INT, ... } Signature;

void do_call(const void *userfunction, const void *args, Signature sig)
{
  switch(signature)
  {
    case VOID_INT:
    {
      int x = *(int *) args;
      void (*f)(int) = userfunction;
      f(x);
      break;
    }
    case VOID_INT_DOUBLE:
    ...
  }
}

ولكن من الواضح تماما أن هذا لا يعيش في نفس القارة كتطوير. يمكنك بالطبع إنشاء هذا الرمز التلقائي، لبعض أنواع المعقولة من أنواع المرسل وأنواع الوسيطة. كنت لا تزال ستكون قليلا في البرد لمؤشرات وظيفة الصب إلى / من void *, ، ولكن هذا قد يكون مقبولا. ما زلت لا تزال تعمل دائما على تخفيف إحداث شخص يقوم بتعليمك توقيعا أنك لم يكن لديك شفرة تم إنشاؤها مسبقا.

نصائح أخرى

الدفع libffi.. وبعد تتيح هذه المكتبة استدعاء وظيفة مع مجموعة من المعلمات المحددة في وقت التشغيل.

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