كيف يمكنني إرسال بريد المرسل، إذا ما تم كسر دعمي مترجم للمؤشرات إلى وظائف؟

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

  •  08-07-2019
  •  | 
  •  

سؤال

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

وهنا كيف لي تنفيذها أصلا الرمز (في VC):

/* Relevant parts of header file  */
typedef struct command {
  const char *code;
  void *set_dispatcher;
  void *get_dispatcher;
  const char *_description;
} command_t;

#define COMMAND_ENTRY(label,dispatcher,description) {(const char*)label, &set_##dispatcher, &get_##dispatcher, (const char*)description} 


/* Dispatcher data structure in the C file */
const command_t commands[] = {
  COMMAND_ENTRY("DH", Dhcp, "DHCP (0=off, 1=on)"),
  COMMAND_ENTRY("IP", Ip, "IP Address (192.168.1.205)"),
  COMMAND_ENTRY("SM", Subnet, "Subunet Mask (255.255.255.0)"),
  COMMAND_ENTRY("DR", DefaultRoute, "Default router (192.168.1.1)"),
  COMMAND_ENTRY("UN", Username, "Web username"),
  COMMAND_ENTRY("PW", Password, "Web password"),
  ...
}


/* After matching the received command string to the command "label", the command is dispatched */
if (pc->isGetter)
  return ((get_fn_t)(commands[i].get_dispatcher))(pc);
else
  return ((set_fn_t)(commands[i].set_dispatcher))(pc);
  }

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

وماذا كنت أفكر في القيام تتحرك جميع خطوط COMMAND_ENTRY إلى منفصلة تشمل الملف. ثم يلتف التي تشمل ملف مع اختلاف رقم تعريف و#undefines. شيء من هذا القبيل:

/* Create enum's labels */
#define COMMAND_ENTRY(label,dispatcher,description) SET_##dispatcher, GET_##dispatcher
typedef enum command_labels = {
#include "entries.cinc"
  DUMMY_ENUM_ENTRY} command_labels_t;
#undefine COMMAND_ENTRY


/* Create command mapping table */
#define COMMAND_ENTRY(label,dispatcher,description) {(const char*)label, SET_##dispatcher, GET_##dispatcher, (const char*)description} 
const command_t commands[] = {
#include "entries.cinc"
  NULL /* dummy */ };
#undefine COMMAND_ENTRY

/*...*/

int command_dispatcher(command_labels_t dispatcher_id) {
/* Create dispatcher switch statement */
#define COMMAND_ENTRY(label,dispatcher,description) case SET_##dispatcher: return set_##dispatcher(pc); case GET_##dispatcher: return get_##dispatcher(pc);
switch(dispatcher_id) {
#include "entries.cinc"
default:
  return NOT_FOUND;
}
#undefine COMMAND_ENTRY
}

لا أحد يرى أفضل طريقة للتعامل مع هذا الوضع؟ للأسف، 'الحصول مترجم آخر' ليس خيارا قابلا للتطبيق. : (

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

وهكذا ليس لدي وسيلة سهلة لاستخراج عنوان ظائفها بالتمسك به.

و--- تحرير # 2: آه، نعم، واستخدام الفراغ * (مجموعة | الحصول على) وكان _dispatcher بلدي محاولة لمعرفة ما اذا كانت المشكلة مع typedefine من المؤشرات ظائفها. في الأصل، كان لي

typedef int (*set_fn_t)(cmdContext_t *pCmdCtx);
typedef int (*get_fn_t)(cmdContext_t *pCmdCtx);

typedef struct command {
  const char *code;
  set_fn_t set_dispatcher;
  get_fn_t get_dispatcher;
  const char *_description;
} command_t;
هل كانت مفيدة؟

المحلول

ويجب عليك أن تحاول تغيير struct command بحيث مؤشرات الدالة لديها نوع الفعلي:

typedef struct command {
  const char *code;
  set_fn_t set_dispatcher;
  get_fn_t get_dispatcher;
  const char *_description;
} command_t;

للأسف، ليست مضمونة مؤشرات الدالة لتكون قادرة على تحويل إلى / من مؤشرات باطلة (وهذا لا ينطبق إلا على مؤشرات إلى الكائنات).

ما هي البيئة جزءا لا يتجزأ؟


وبالنظر إلى المعلومات المنشورة في التحديثات على السؤال، وأرى أنه حقا مترجم تنصتت.

وأعتقد أن الحل المقترح يبدو معقولا جدا - انها ربما على غرار ما كنت قد حان حتى مع

.

نصائح أخرى

لا حاجة لمؤشر الدالة في الواقع لتناسب في الفراغ *. هل يمكن أن تحقق للتأكد من أن القيمة التي تقوم بطلبه هو في الواقع عنوان الدالة. إذا لم يكن كذلك، استخدام نوع مؤشر دالة في البنية: إما get_fn_t، أو IIRC الفراغ (*) (الفراغ) مكفولة لتكون متوافقة مع أي نوع وظيفة مؤشر

وتحرير: موافق، على افتراض أن يدعو من حيث القيمة لا يمكن إدخالها على العمل، لا أستطيع التفكير في طريقة أكثر إتقانا لتفعل ما تريد من السيارات توليد بيان التبديل. هل يمكن ربما استخدام على غرار ASP وضع المعالج قبالة الجاهزة للاستخدام لروبي / بيثون / بيرل / PHP / مهما قبل C المعالج. شيء من هذا القبيل:

switch(dispatcher_id) {
<% for c in commands %>
    case SET_<% c.dispatcher %>: return set_<% c.dispatcher %>(pc); 
    case GET_<% c.dispatcher %>: return get_<% c.dispatcher %>(pc);
<% end %>
default:
    return NOT_FOUND;
}

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

ويمكنك الحصول على البائع لإصلاح مترجم؟

وإلى أي مدى هو-مؤشر إلى وظيفة مكسورة؟

إذا يسمح المترجم لك للحصول على عنوان وظيفة (أنا من C ++، ولكن &getenv ما أعنيه)، هل يمكن أن التفاف الاشياء اصطلاح استدعاء في المجمع.

وكما قال، أنا C ++ ssie، ولكن شيئا في طريق

; function call
push [arg1]
push [arg2]
call [command+8] ; at the 4th location, the setter is stored
ret

وإذا كان هذا هو حتى كسر، هل يمكن تحديد مجموعة من المؤشرات extern void* التي تحدد، مرة أخرى، في التجمع.

ومحاولة بناء الجملة التالي:

وعودة (* ((get_fn_t) أوامر [أنا] .get_dispatcher)) (الكمبيوتر)؛

ولقد كانت لحظة منذ ان كنت فعلت C & ظيفة المؤشرات، لكنني أعتقد بناء الجملة C الأصلي المطلوب مؤشرات الدالة * عندما dereferencing لكن معظم المجمعين تتيح لك الابتعاد دون ذلك.

هل لديك الوصول إلى خريطة الارتباط؟ إذا كان الأمر كذلك، ربما يمكنك الإختراق طريقك حول الطاولة وظيفة مؤشر متزعزع:

unsigned long addr_get_dhcp = 0x1111111;
unsigned long addr_set_dhcp = 0x2222222; //make these unique numbers.

/* Relevant parts of header file  */
typedef struct command {
  const char *code;
  unsigned long set_dispatcher;
  unsigned long get_dispatcher;
  const char *_description;
} command_t;

#define COMMAND_ENTRY(label,dispatcher,description) {(const char*)label, 
    addr_set_##dispatcher, addr_get_##dispatcher, (const char*)description} 

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

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

وربما، وكنت بحاجة الى ان ننظر في هيكل مرة أخرى:

typedef struct command {
  const char *code;
  void *set_dispatcher; //IMO, it does not look like a function pointer...
  void *get_dispatcher; //more like a pointer to void
  const char *_description;
} command_t;

ودعونا نقول المرسلون لديك تعريف الدالة مماثل التالية:

//a function pointer type definition
typedef int (*genericDispatcher)(int data);

ونفترض أن المرسلون من مثل أدناه:

int set_DhcpDispatcher(int data) { return data; }
int get_DhcpDispatcher(int data) { return 2*data; }

وهكذا، الهيكل المنقح سيكون:

typedef struct command {
  const char *code;
  genericDispatcher set_dispatcher; 
  genericDispatcher get_dispatcher; 
  const char *_description;
} command_t;

والكلي سوف يكون لديك:

#define COMMAND_ENTRY(label,dispatcher,description) \
{   (const char*)label, \
    set_##dispatcher##Dispatcher, \
    get_##dispatcher##Dispatcher, \
    (const char*)description } 

وبعد ذلك، يمكنك تعيين مجموعة كالمعتاد:

int main(int argc, char **argv)
{
    int value1 = 0, value2 = 0;

    const command_t commands[] = {
      COMMAND_ENTRY("DH", Dhcp, "DHCP (0=off, 1=on)")
    };

    value1 = commands[0].set_dispatcher(1);
    value2 = commands[0].get_dispatcher(2);

    printf("value1 = %d, value2 = %d", value1, value2);

    return 0;
}

وتصحيح لي إذا كنت مخطئا في مكان ما ...؛)

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