No. C không cho phép bạn thực hiện điều đó trực tiếp.
Trong C cách tiêu chuẩn để xử lý callbacks đang sử dụng con trỏ ngữ cảnh:
void register_callback(void (*cback)(void *context, int data),
void *context);
điều này có nghĩa rằng bạn sẽ vượt qua một chức năng mà sẽ chấp nhận một void *
ngoài các thông số bình thường mà gọi lại nên xử lý (trong trường hợp trên là số nguyên) và bạn cũng sẽ chuyển một số void *
mà bạn muốn được trả lại.
Điều này void *
thường trỏ đến struct
sẽ chứa tất cả thông số hoặc dữ liệu bổ sung bạn cần trong gọi lại và sử dụng phương pháp này thư viện không phụ thuộc vào ngữ cảnh này là gì. Nếu callback không cần bất kỳ ngữ cảnh nào, bạn chỉ cần truyền con trỏ NULL là context
và bỏ qua tham số đầu tiên khi được gọi từ thư viện.
Thứ gì đó khá giả mạo và không chính thức nhưng đôi khi được thực hiện là nếu ngữ cảnh là dữ liệu đơn giản phù hợp với kích thước của void *
(ví dụ: số nguyên) và nếu môi trường của bạn không có vấn đề gì với nó bạn có thể lừa thư viện bằng cách chuyển một số giả void *
chỉ là một số nguyên và bạn chuyển đổi nó thành một số nguyên khi được gọi từ thư viện (điều này giúp người gọi không phân bổ ngữ cảnh và quản lý thời gian của nó).
Về cách làm thế nào để đánh lừa các ngôn ngữ để tránh hạn chế này (vẫn còn lại trong đất của C xách tay) Tôi có thể nghĩ rằng một số hack:
Đầu tiên chúng tôi phân bổ một vũng hai đối số callbacks và dữ liệu bối cảnh
void (*cbf[6])(int, int);
int ctx[6];
thì chúng tôi viết (hoặc macro tạo) chức năng mà chúng tôi muốn đăng ký và sẽ gọi phiên bản hai đối số.
void call_with_0(int x) { cbf[0](ctx[0], x); }
void call_with_1(int x) { cbf[1](ctx[1], x); }
void call_with_2(int x) { cbf[2](ctx[2], x); }
void call_with_3(int x) { cbf[3](ctx[3], x); }
void call_with_4(int x) { cbf[4](ctx[4], x); }
void call_with_5(int x) { cbf[5](ctx[5], x); }
Chúng tôi cũng lưu trữ chúng trong một hồ bơi, nơi họ đang được phân bổ và deallocated:
int first_free_cback = 0;
int next_free_cback[6] = {1, 2, 3, 4, 5, -1};
void (*cbacks[6])(int) = { call_with_0,
call_with_1,
call_with_2,
call_with_3,
call_with_4,
call_with_5 };
Sau đó để ràng buộc các tham số đầu tiên chúng ta có thể làm điều gì đó như
void (*bind(void (*g)(int, int), int v0))(int)
{
if (first_free_cback == -1) return NULL;
int i = first_free_cback;
first_free_cback = next_free_cback[i];
cbf[i] = g; ctx[i] = v0;
return cbacks[i];
}
nhưng ràng buộc chức năng cũng phải được giải quyết rõ ràng
int deallocate_bound_cback(void (*f)(int))
{
for (int i=0; i<6; i++) {
if (f == cbacks[i]) {
next_free_cback[i] = first_free_cback;
first_free_cback = i;
return 1;
}
}
return 0;
}
Đóng cửa thực sự là cách để đạt được điều này trong "C". LibFFI cung cấp các bao đóng và có thể di chuyển đến hầu hết các hệ điều hành chính: http://sourceware.org/libffi/ –
@BojanNikolic Điểm tốt, và libffi phổ biến hơn nhiều so với tấm bạt lò xo. Một câu trả lời với ví dụ na giải quyết vấn đề của OP bằng cách sử dụng libffi có thể được đánh giá cao. – user4815162342