I am trying to wrap a library for porting purpose. The library exposes a function say -
fooLib(int , char , function pointer A);
signature of the function pointer A is
void handler(DataFormat);
where DataFormat is a struct
I don't want my wrapper to expose this library's callback function. I want to create a different function that should be used by the consumers of my wrapper, say
int handlerNew(NewDataFormat);
where NewDataFormat is my struct
The question now is how can I link these two functions? Whenever the library calls handler I want it to call my callback handlerNew after filling up the NewDataFormat struct from the DataFormat.
As long as you don't need thread safety, this is not hard. You just have to provide a private (static) handler with the library's interface that transforms the library data struct into your wrapped version, then calls your callback with that as an argument. Your interface will look like:
// wrapped_foo_lib.h
typedef struct { ... } NewDataFormat;
typedef void (*WRAPPED_CALLBACK)(NewDataFormat);
void wrappedFooLibCall(int x, char c, WRAPPED_CALLBACK cb);
Your implementation, which the client never gets to see is:
// wrapped_foo_lib.c
// This static var makes this module _not_ thread safe.
static WRAPPED_CALLBACK wrapped_callback;
static void private_handler(DataFormat data) {
NewDataFormat new_data = ...; // extract new_data from data
wrapped_callback(new_data);
}
void wrappedFooLibCall(int x, char c, WRAPPED_CALLBACK cb) {
wrapped_callback = cb;
foo_lib(x, c, private_handler);
}
The non-thread safety is why every API callback should include a void * that you get to define, which is passed on to the callback. I.e. your furnished library should be defined as
fooLib(int, char, void (*)(DataFormat, void *env));
void handler(DataFormat, void *env);
Now when you call fooLib, you furnish any struct at all as env, and it's passed back to you. This way you can dispense with the static variable in the wrapper:
// wrapped_foo_lib.c
typedef struct { WRAPPED_CALLBACK wrapped_callback; } ENV;
static void private_handler(DataFormat data, void *void_env) {
ENV *env = (ENV*)void_env;
NewDataFormat new_data = ...; // extract new_data from data
env->wrapped_callback(new_data);
}
void wrappedFooLibCall(int x, char c, WRAPPED_CALLBACK cb) {
ENV env[1] = {{ cb }};
foo_lib(x, c, env);
}
This is thread safe because ENV is stack allocated. A nice example of this done well is the libpng.
Feel free to update the C90 to more modern syntax.
Related
I use the Aeron client implementation in C. And I need to make closure. But there are no closures in C...
For example:
void poll_handler(void *clientd, const uint8_t *buffer, size_t length, aeron_header_t *header)
{
aeron_subscription_t* subscription = (aeron_subscription_t*)clientd;
aeron_subscription_constants_t subscription_constants;
aeron_header_values_t header_values;
aeron_subscription_constants(subscription, &subscription_constants)
aeron_header_values(header, &header_values);
// How to get some_data here?
}
void some_func(int some_data)
{
aeron_fragment_assembler_create(fragment_assembler, poll_handler, subscription)
}
I tried using Clang blocks extension, but there is no function implementation that accepts block.
How can I get some local data in handler?
The aeron_fragment_assembler_create function takes a pointer to any structure as the third parameter. It doesn't need to be the aeron_subscription_t*.
You can create your own structure, initialize it with the necessary data and pass a pointer to it. And for convenience, you can save a pointer to aeron_subscription_t in the structure.
More or less like this:
typedef struct some_data_t {
aeron_subscription_t* subscription;
// ...
} some_data_t ;
void poll_handler(void *clientd, const uint8_t *buffer, size_t length, aeron_header_t *header)
{
some_data_t * some_data = (some_data_t *) clientd;
aeron_subscription_t* subscription = some_data->subscription;
// ...
}
void some_func(some_data_t* some_data)
{
aeron_fragment_assembler_create(fragment_assembler, poll_handler, some_data)
}
I am new to C and can't yet freely navigate trough my program memory. Anyways, I am creating a static memory data type (gc_menu) that should hold a pointer to created at execution time structure (mcl_items).
For simplicity mcl_items structure have one virtual method (push) that is going to be run inside of gc_menu_add_item and also assigned to the gc_menu static space. push saves an menu item name (letter) and method to mcl_item virtual object.
mcl_items.h code:
[...]
typedef struct Items_t {
int8_t size;
char names[64];
void (*methods[64])();
// Interface
void (*push)(struct Items_t *self, char c, void (*method)());
}mcl_items;
mcl_items *new_mcl_items();
void mcl_items_push(mcl_items *self, char c, void (*method)());
mcl_items.c code:
[...]
#include "mcl_items.h"
mcl_items *new_mcl_items() {
fprintf(stderr, "MCL_Items: Generating a new set of mcl_items..");
// Build a virtual object
mcl_items *items = calloc(1, sizeof(struct Items_t));
items->push = mcl_items_push;
// Set data
items->size = 0;
return items;
}
void mcl_items_push(mcl_items *self, char c, void (*method)()) {
fprintf(stderr, "MCL_Items: pushing a new item..");
self->names[self->size] = c;
self->methods[self->size] = method;
self->size ++;
}
gc_menu.h code:
#include "items.h"
typedef struct {
// Interface
void (*add_item)(char c, void (*method)());
// Data
mcl_items *items;
}__gc_menu;
extern __gc_menu const gc_menu;
gc_menu.c code:
static void gc_menu_add_item(char c, void (*method)) {
fprintf(stderr, "GC_Menu: Passing an new item..");
fprintf(stderr, "length = %i\n", gc_menu.items->size);
gc_menu.items->push(gc_menu.items, c, method);
}
__gc_menu const gc_menu = {gc_menu_add_item, // Virtual methods
new_mcl_items}; // Data
After callng gc_menu.add_item the segmentation fault occurs and gc_menu.items->size is equal to 72, not 0 as is defined in the definition of new_mcl_items.
main.c code:
gc_menu.add_item('q', xw->end(xw));
GC_Menu: Passing an new item..length = 72
[1] 66021 segmentation fault (core dumped) ./3D_scean
So what am I doing wrong? Why is there such a weird data written to instances of my gc_menu.items?
You've initialized gc_menu.items to new_mcl_items, i.e. a pointer to the function new_mcl_items (which should give you a warning since it is of type mcl_items *(*)(void) and not mcl_items *).
It looks like what you want is to actually call the function new_mcl_items() and set gc_menu.items to the value that new_mcl_items() returns. You can't do this with an initializer; initializers of global or static objects must be known at compile or link time. Standard C doesn't have "constructors".
So you'll have to remove the const from the declaration and definition of gc_menu, and add code to main (or some function called by main, etc) to initialize gc_menu.items at run time.
gc_menu.h:
extern __gc_menu gc_menu;
gc_menu.c:
__gc_menu gc_menu = {
gc_menu_add_item,
NULL // or whatever else you like
};
main.c or whatever you have called it:
int main(void) {
// ...
gc_menu.items = new_mcl_items();
// ...
}
I don't have much experience in Object oriented programming.I am trying to create an object in c which will have its own methods.
I have declared structure which have pointers to function. All instance of this variable are going to point same function. But currently I need to initialize every instance of variable as in main (Line 1 and Line 2). So is there any method that will initialize its default value when I declare it?
#include <stdio.h>
#include <stdlib.h>
typedef struct serialStr Serial;
struct serialStr
{
void(*init)(Serial*);
void(*open)();
void(*close)();
};
void open()
{
printf("Open Port Success\n");
return;
}
void close()
{
printf("Close port Success\n");
return;
}
void init(Serial* ptr)
{
ptr->open = open;
ptr->close = close;
}
int main()
{
Serial serial,serial_2;
serial.init = init;
serial.init(&serial); // Line1
serial_2.init = init;
serial_2.init(&serial_2); // Line2
serial.open();
//rest of code
serial.close();
serial_2.open();
serial_2.close();
return 0;
}
In C, the standard way would be to declare an initializer macro:
#define SERIAL_INITIALIZER { .init = init, .open = open, /* and others */ }
Serial serial = SERIAL_INITIALIZER;
In most cases in C there is simply no need for dynamic intialization of variables. You only need it for malloced objects.
C++ add some automatization by calling constructor/destructor. In pure C is no way to do so. You should do all steps manually: create and initialize object (call constructor-like function for structure), call functions by pointers from the structure instance, call destructor (it should destroy the instance and free related resources).
If is no polymorphism in your task then use simple way - without pointers to functions, but each function (method) should take pointer to the object.
Common case example:
struct MyStruct
{
// data
};
struct MyStruct* createMyStruct(/* maybe some input */)
{
// create, init and return the structure instance
}
void destoyMyStruct(struct MyStruct* obj)
{
// free resources and delete the instance
}
void doSomeAction(struct MyStruct* obj /* , some other data */)
{
// ...
}
int main()
{
struct MyStruct* object = createMyStruct();
doSomeAction(object);
destoyMyStruct(object);
return 0;
}
Edit 1: macro is only for very simple cases and error-prone way.
Typically, you would do this through "opaque type". Meaning that you declare an object of incomplete type in your header:
typedef struct Serial Serial;
And then in the C file, you place the actual struct definition. This will hide the contents of the struct to the caller (private encapsulation). From your constructor, you could then set up private member functions:
struct Serial
{
void(*init)(void);
void(*open)(void);
void(*close)(void);
};
// private member functions:
static void open (void);
...
// constructor:
Serial* SerialCreate (void)
{
Serial* s = malloc(sizeof (*s));
...
s->open = open;
return s;
}
This means that if you wish to inherit the class, you will only need to change the constructor.
Though of course, if you wish to implement true polymorphism, you don't want to change any code. You could solve this by passing the init function as parameter to the constructor.
header file:
typedef void init_func_t (void);
c file:
// constructor:
Serial* SerialCreate (init_func_t* init)
{
Serial* s = malloc(sizeof (*s));
...
init();
return s;
}
And then from the init function in the inherited class, set all private member functions.
How do I pass a delegate to an external C function taking a function pointer, in D?
Let me cross post what I said on the newsgroup:
How do I pass a delegate to an external C function taking a
function pointer?
You can't do it directly in general, unless you can modify the C
function, then you can hack around it, but a delegate and a
regular function pointer are pretty different animals.
But perhaps you can magic hack it. Observe:
// a C function that needs a plain function
extern(C) void test(void function() f) {
// pretend this is implemented in C
f();
}
// just create a random delegate
void delegate() foo(int a) {
return { import std.stdio; writeln(a); };
}
// what we want to work
void main() {
auto dg = foo(10);
dg(); // works
//test(dg); // won't work
test(bindDelegate(dg)); // we want this
}
// transform delegate into pointer..
import std.traits;
auto bindDelegate(T, string file = __FILE__, size_t line = __LINE__)(T t) if(isDelegate!T) {
static T dg;
dg = t;
extern(C)
static ReturnType!T func(ParameterTypeTuple!T args) {
return dg(args);
}
return &func;
}
What bindDelegate does is create a special static variable and
function for that specific call. It is as if we wrote a separate
function and global to hold it.
The __FILE__, __LINE__ things are a filthy hack to make it
instantiate a separate variable+function pair for different
lines so the global variable holding the delegate won't be so
easily overwritten.
I have started to review callbacks. I found this link on SO:
What is a "callback" in C and how are they implemented? It has a good example of callback which is very similar to what we use at work. However, I have tried to get it to work, but I have many errors.
#include <stdio.h>
/* Is the actual function pointer? */
typedef void (*event_cb_t)(const struct event *evt, void *user_data);
struct event_cb
{
event_cb_t cb;
void *data;
};
int event_cb_register(event_ct_t cb, void *user_data);
static void my_event_cb(const struct event *evt, void *data)
{
/* do some stuff */
}
int main(void)
{
event_cb_register(my_event_cb, &my_custom_data);
struct event_cb *callback;
callback->cb(event, callback->data);
return 0;
}
I know that callbacks use function pointers to store an address of a function. But there are a few things that I find I don't understand:
What is meant by "registering the callback" and "event dispatcher"?
This code compiles and runs under GCC with -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;
}
You probably need to review whether the call back function gets the whole struct event_cb or not - usually, you'd just pass the data because, as demonstrated, otherwise you have two sources of the same information (and a spare copy of the pointer to the function that you're in). There is a lot of cleanup that can be done on this - but it does work.
A question in the comments asks: Is this a good example of a callback?
Succinctly, no - but in part because there isn't sufficient infrastructure here.
In a sense, you can think of the comparison function passed to the qsort() or bsearch() functions as a callback. It is a pointer to a function that is passed into the generic function that does what the generic function cannot do for itself.
Another example of a callback is a signal handler function. You tell the system to call your function when the event - a signal - occurs. You set up the mechanisms ahead of time so that when the system needs to call a function, it knows which function to call.
The example code is attempting to provide a more elaborate mechanism - a callback with a context. In C++, this would perhaps be a functor.
Some of the code I work with has very fussy requirements about memory management - when used in a particular context. So, for testing, I use malloc() et al, but in production, I have to set the memory allocators to the specialized allocators. Then I provide a function call in the package so that the fussy code can override the default memory allocators with its own surrogate versions - and provided the surrogates work OK, the code will behave as before. Those are a form of callback - again, a form that does not need much (or anything) in the way of user context data.
Windowing systems have event handlers (callbacks) that are registered and that the GUI main event loop will call when events occur. Those usually need user context as well as the event-specific information provided by the GUI system.
What is meant by "registering the callback" and "event dispatcher"?
"registering the callback" is the act of telling the underlying system which precise function to call, and (optionally) with which parameters, and possibly also for which particular class of events that callback should be invoked.
The "event dispatcher" receives events from the O/S (or GUI, etc), and actually invokes the callbacks, by looking in the list of registered callbacks to see which are interested in that event.
Without the compiler output it's hard, but I can see a few problems;
int event_cb_register(event_ct_t cb, void *user_data);
Should be
int event_cb_register(event_cb_t cb, void *user_data);
The my_custom_data variable does not exist when it's used here;
event_cb_register(my_event_cb, &my_custom_data);
This pointer is never initialized;
struct event_cb *callback;
And in;
callback->cb(event, callback->data);
You cannot pass the name of a type ('event') to a function, you must pass an instance of that type.
int event_cb_register(event_ct_t cb, void *user_data);
What is that type event_ct_t? Do you mean event_cb_t?
struct event_cb *callback;
Creates an uninitialized pointer to a structure event_cb. Note mostly this points to garbage.
callback->cb(event, callback->data);
You are trying to call garbage. You need initialization:
struct event_cb callback;
callback.cb = my_event_cb;
callback.data = 42;
or some such stuff.
Registering a callback means that you are specifying which function should be called when the event of interest occurs. Basically you are setting the function pointer when registering a callback.
You created a pointer of the struct you declared, but it does not point to anything:
struct event_cb *callback;
You should just create a type of your struct:
struct event_cb callback;
and then pass its address to the functions.