Mã này biên dịch và chạy dưới GCC với -Wall.
#include <stdio.h>
struct event_cb;
typedef void (*event_cb_t)(const struct event_cb *evt, void *user_data);
struct event_cb
{
event_cb_t cb;
void *data;
};
static struct event_cb saved = { 0, 0 };
void event_cb_register(event_cb_t cb, void *user_data)
{
saved.cb = cb;
saved.data = user_data;
}
static void my_event_cb(const struct event_cb *evt, void *data)
{
printf("in %s\n", __func__);
printf("data1: %s\n", (const char *)data);
printf("data2: %s\n", (const char *)evt->data);
}
int main(void)
{
char my_custom_data[40] = "Hello!";
event_cb_register(my_event_cb, my_custom_data);
saved.cb(&saved, saved.data);
return 0;
}
Có thể bạn cần xem lại chức năng gọi lại có toàn bộ cấu trúc event_cb hay không - thông thường, bạn chỉ chuyển dữ liệu bởi vì, như được minh họa, nếu không bạn có hai nguồn giống nhau (và một bản sao dự phòng của con trỏ đến hàm bạn đang ở). Có rất nhiều dọn dẹp có thể được thực hiện về điều này - nhưng nó hoạt động.
Câu hỏi trong nhận xét hỏi: Đây có phải là ví dụ hay về gọi lại không?
Ngắn gọn, không - nhưng một phần vì không có đủ cơ sở hạ tầng ở đây.
Trong ý nghĩa, bạn có thể nghĩ rằng hàm so sánh được chuyển đến các hàm qsort()
hoặc bsearch()
làm gọi lại. Nó là một con trỏ trỏ tới một hàm được chuyển vào hàm generic mà những gì mà hàm generic không thể làm cho chính nó.
Ví dụ khác về gọi lại là chức năng xử lý tín hiệu. Bạn yêu cầu hệ thống gọi hàm của bạn khi sự kiện - một tín hiệu - xảy ra. Bạn thiết lập các cơ chế trước thời hạn để khi hệ thống cần gọi một hàm, nó biết hàm nào cần gọi.
Mã mẫu đang cố gắng cung cấp cơ chế phức tạp hơn - gọi lại với ngữ cảnh. Trong C++, điều này có lẽ sẽ là một hàm functor.
Một số mã tôi làm việc có yêu cầu rất cầu kỳ về quản lý bộ nhớ - khi được sử dụng trong một ngữ cảnh cụ thể. Vì vậy, để thử nghiệm, tôi sử dụng malloc()
et al, nhưng trong sản xuất, tôi phải thiết lập bộ cấp phát bộ nhớ cho các bộ phân bổ chuyên dụng. Sau đó, tôi cung cấp một cuộc gọi hàm trong gói để mã cầu thủ có thể ghi đè lên các bộ cấp phát bộ nhớ mặc định bằng các phiên bản thay thế của riêng nó - và cung cấp cho người thay thế hoạt động OK, mã sẽ hoạt động như trước. Đó là một dạng gọi lại - một lần nữa, một biểu mẫu không cần nhiều (hoặc bất kỳ thứ gì) trong cách dữ liệu ngữ cảnh của người dùng.
Hệ thống cửa sổ có trình xử lý sự kiện (gọi lại) được đăng ký và vòng lặp sự kiện chính GUI sẽ gọi khi sự kiện xảy ra. Những người này thường cần bối cảnh người dùng cũng như thông tin sự kiện cụ thể được cung cấp bởi hệ thống GUI.
Tại sao không bao gồm lỗi của bạn? –