מימוש של CALLBACK ב-C

voguemaster

New member
מימוש של CALLBACK ב-C

חבר'ה אני מחפש רעיונות איך מממשים CALLBACKS ב-C (בלבד) בצורות שונות. תמיד אפשר לקבל מצביע לפונק' מטיפוס מסוים ופשוט לקרוא לה ב"לולאה" אבל תהיתי איזה עוד רעיונות חמודים יש לכם.
 

erezsh

New member
לא בטוח שהבנתי את הכוונה שלך

אבל ישר הזכרת לי שיטה בה ספריית Allegro משתמשת- יש לה פונקציות circle, line וכד', אלא מה, שהן לא מציירות על המסך ולא כלום, אלא קוראות לפונקציית callback שמקבלת מיקום x,y וצבע, ותפקידה הוא לצייר את הפיקסל. השימוש בשיטה זו הוא איטי, אבל מה היופי בו - בקלות אפשר במקום פונקצייה שמציירת את הפיקסל לכתוב פונקצייה שכותבת את ערכי הפיקסלים לקובץ, או עושה אפקט מיוחד בעת ציור הפיקסל, או פונקצייה שבודקת collision על צורה גיאומטרית וכו'. כל זאת, בלי לכתוב את פונקציית ה"ציור" (מעקב אחר כל נקודות הצורה) בעצמך. זה לא בוצע בדרך המיטבית, אבל הרעיון מרענן. (כמובן של-allegro יש גם פונקציות ציור נורמליות)
 

voguemaster

New member
נחמד...

אני רוצה בעיקרון שהמתכנת יוכל לכתוב handler לפרוטוקול כלשהו בעצמו, לפי סוג המידע שמגיע. ומעבר לכך, אני מאוד רוצה לאפשר ממשק שבו יהיה קל לעבד את המידע הזה. בעזרת CALLBACK אני יכול לבצע איטרציה על כל המידע ולשלוח אותו ל-HANDLER המתאים.
 

voguemaster

New member
וכמובן

שיהיה אפשר להפריד בין ה-handler לשאר המודול כך שיהיה קל לכתוב handlerים חדשים..
 

eyalbd

New member
בסופו של דבר אין לך משהו אחר

הכל מסתכם בקריאה לפונקציה ע"י פוינטר. ה-API במערכות GUI מבוסס כולו על זה. גם בספריית C הסטנדרטית הממשק לפונקציה שמסופקת ע"י משתמש הוא ע"י מצביע לפונקציה. אפשר לממש את זה בצורות מתוחכמות - לדוגמא לממש פונקציות וירטואליות ב-C ע"י vtbl ו- vptr. אפשר שמבנה יכיל פוינטרים לפונקציה ואז יש סינטקס דומה לקריאה ב++C.
 

voguemaster

New member
אוקיי

אני מניח שאתה צודק. אולי אני איישם משהו שדומה ל-struct עם טבלת מצביעים.
 

eyalbd

New member
תוכל לשכלל את הדוגמה הזאת

אני מקווה שלא תיבהל אבל רק בשביל התרגיל כתבתי מימוש של פונקציות וירטואליות ב-C. תודה שנתת לי הזדמנות לכתוב סוף סוף דוגמא כזו. אני דווקא נהניתי. יצרתי את ההיררכיה הקלסית של צורות. erezsh הזכיר את אלגרו - למיטב ידיעתי המימוש דומה לזה. זה פחות או יותר מה שקומפיילר ++C יותר כאשר משתמשים בפולימורפיזם. היתרון של השיטה ע"פ מצביעים הוא שתוספת הגודל לכל אובייקט היא פוינטר אחד. כלומר בלתי תלוי במספר ה"פונקציות הוירטואליות". אייל
/* ***************************************************** * * c_virt.c * * Example of implementation of virtual functions in C * * Written by Eyal Ben-David, Dec 09, 2003. * * Public Domain * ****************************************************** */ #include <stdio.h> /* ********************************* * * "Pure Virtual" Shape structure * ********************************* */ /* "Generic" Pointer to function */ typedef void (*VTable)(); typedef struct Shape { VTable* vptr; } Shape; void display_perimeter(Shape* p) { (*(p->vptr)[0])(p); } void display_area(Shape* p) { (*(p->vptr)[1])(p); } void draw_shape(Shape* p) { (*(p->vptr)[2])(p); } /*---------------------------------------*/ /* ********************************* * * "class Circle : public Shape" * ********************************* */ #define MY_PI (3.141593) typedef struct Circle { Shape shape; double radius; } Circle; void circle_perimeter(Circle* p) { printf("Circle Perimeter=%g\n", 2 * MY_PI * p->radius); } void circle_area(Circle* p) { double r = p->radius; printf("Circle Area=%g\n", MY_PI * r * r); } void draw_circle(Circle* p) { printf("Drawing Circle with radius=%g...\n", p->radius); } void circle_ctor(Circle* p, double r) { static VTable circle_vtbl[] = { &circle_perimeter, &circle_area, &draw_circle }; p->shape.vptr = circle_vtbl; p->radius = r; } /*---------------------------------------*/ /* ********************************* * * "class Square : public Shape" * ********************************* */ typedef struct Square { Shape shape; double side; } Square; void square_perimeter(Square* p) { printf("Square Perimeter=%g\n", 4 * p->side); } void square_area(Square* p) { printf("Square Area=%g\n", p->side * p->side); } void draw_square(Square* p) { printf("Drawing Square with side=%g...\n", p->side); } void square_ctor(Square* p, double s) { static VTable square_vtbl[] = { &square_perimeter, &square_area, &draw_square }; p->shape.vptr = square_vtbl; p->side = s; } /*---------------------------------------*/ int main() { Circle c; Square s; circle_ctor(&c, 5); square_ctor(&s, 5); display_perimeter(&c); display_area(&c); draw_shape(&c); printf("\n"); display_perimeter(&s); display_area(&s); draw_shape(&s); return 0; }​
 

voguemaster

New member
אהבתי את המימוש

חביב ביותר, קבל ח"ח
. אני אפילו אשמור את זה למזכרת... (אני יכול לכתוב משהו דומה אבל לא מזיק אף פעם
) מה שמעניין אותי ספציפית כתוצאה מהדוגמא שלך זה איך הקומפיילר בעצם מייצר את ה-vtbl. כלומר, אצלך זה מערך של מצביעים כמובן, אבל הוא בגודל קבוע. השאלה המעניינת היא האם הקומפיילרים עובדים בצורה זהה או שיש להם מנגנון ליצירת מערכים משתנים בגודל
ועוד דבר שיכול להיות מעניין הוא איך הם מיישמים את הירושה. כי ב-C (וזה גם נובע מהדוגמא שלך) נדמה לי שאפשר רק ליישם ירושה ע"י הכלה של האובייקט אב באובייקט בן. טוב, אני מניח שכך זה עובד בפועל אבל הקומפיילרים יכולים להוסיף בדיקות type בהתאם.. בכל מקרה, יפה.
 

eyalbd

New member
|כדאי שתקרא את

הספר The C++ Object Model של Lippman. הוא דן שם איך זה ממומש בפועל. קראתי מזמן ואין לי את הספר כיום. גם eckel הסביר את זה באחד מספריו
 
למעלה