Actually I am registering Callback to lower layer of code from upper layer.
So In a c "config file" file I have this :
typedef enum eActivationType
{
TYPE_A = 0,
TYPE_B,
TYPE_C,
}ActivationType_t;
typedef struct Callbacks_s
{
void (*OnJoin)(ActivationType_t Mode);
}NemeusCallbacks_t;
static Callbacks_t Callbacks = {
.OnJoin = OnJoin,
.//I have other callbacks here but I the first one works the other will work
};
static Params_t Params = {
.DefaultActivationType = TYPE_A,
//other params
}
Callbacks_t* GetCallbacks(void)
{
return &Callbacks;
}
Params_t* GetParams(void)
{
return &Params;
}
From the main file I call
typedef void (*OnJoin)(ActivationType_t Mode);
static OnJoinRequest JoinCB;
void Nemeus_Init_ReceiveCallback(OnJoin joinCB)
{
JoinCB = joinCB;
}
And then when I want to use my register callback I can't
...
if( 0 == memcmp(&addr, temp_uint8_array, sizeof(addr)) && NULL != JoinCB)
{
JoinCB(&(*(GetParams())->DefaultActivationType));
}
...
The error I have is : invalid type argument of '->' (have 'int').
I think it deals with the adress of GetParams that I want to dereference as adress are store in int.
It is quite complicated for me to understand whats going on but as I am a begginer I want to learn.
I thought that by writing this *(GetParams()) , I can acceed the structure and then by writing this &(*(GetParams())->DefaultActivationType) I can pass the adress of the structur field to the callback
Related
The title is confusing, i tried my best to explain it in a few words but i failed. Here is a better explenation of my problem.
Lets say there's a struct named Object with a bool variable named _active and a function named SetActive().
typedef struct Object
{
bool _active;
void (*SetActive)(bool)
} Object;
Object someObject;
Object someOtherObject;
void SetActive(bool set)
{
/*
if function is being called from someObject, then
someObject._active = set
if function is being called from someOtherObject, then
someOtherObject._active = set
*/
}
(This is an example)
I want SetActive() to set _active of the struct its being called from to set
For example when i call structname.SetActive(true), structname._active = true
How do i do something like this?
void (*SetActive)(bool); is a pointer to a free function. It has no association with any particular object.
In C it's pretty common to supply the object as the first or last argument to the functions acting as member functions. This is needed because C doesn't have actual member functions. To make the association clear to other programmers reading the code, you can prepend all acting "member functions" with the name of the type each function acts upon.
It could look like this:
#include <stdbool.h>
#include <stdlib.h>
typedef struct Object Object;
struct Object {
bool _active;
};
Object *Object_create() {
Object *obj = malloc(sizeof *obj);
if(obj) {
// provide some default init values
*obj = (Object){ ._active = false };
}
return obj;
}
void Object_destroy(Object *obj) {
free(obj);
}
void Object_SetActive(Object *obj, bool set) {
obj->_active = set;
}
int main(void) {
Object *obj = Object_create();
Object_SetActive(obj, true);
Object_destroy(obj);
}
If you really really want to have a poor man OOP, you can do it. But why not switching to a more friendly language?
Basically you would include a function pointer in a struct, iif you plan to override that function in a subclass. This is needed only for polymorphism. In that case you will probably need also a polymorphic destructor for your class.
The problem is that you get pointers to these polymorphic functions in every instance of your objects, so better alternatives are required (vtables, pointer to class CPython style, ...).
The bad news is that now you need to specify the object to access the function pointer and to pass it to the function itself. Which really requires some syntax sugar.
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
typedef struct Object Object;
struct Object {
bool active_;
void (*SetActive)(Object *this, bool status); // This is a virtual method
void (*Destruct)(Object *this); // You will need this for polymorphism
};
void Object_SetActive(Object *this, bool status);
void Object_Destructor(Object *this);
void Object_Constructor(Object *this) { // Default constructor
this->active_ = false;
this->SetActive = Object_SetActive;
this->Destruct = Object_Destructor;
}
void Object_Destructor(Object *this) {
// Nothing to be done here, but maybe when subclassing?
}
void Object_SetActive(Object *this, bool status) {
this->active_ = status;
}
int main(void)
{
Object someObject;
Object_Constructor(&someObject);
Object someOtherObject;
Object_Constructor(&someOtherObject);
someObject.SetActive(&someObject, true);
someOtherObject.SetActive(&someOtherObject, false);
printf("someObject.active_ = %s\n", someObject.active_ ? "true" : "false");
printf("someOtherObject.active_ = %s\n", someOtherObject.active_ ? "true" : "false");
someObject.Destruct(&someObject);
someOtherObject.Destruct(&someOtherObject);
return 0;
}
If you want to waste some time with OOP in C, with macro abuse, you can read this post.
Warning: I don't want to be held responsible for nausea or vomiting caused by reading that post.
With respect to Ted Lyngmo's answer, I'm constructing and destructing already allocated objects. This would need also some new and delete clones.
When creating a vfs using the tcl api how do you get the current filesystem in Tcl_Filesystem.pathInFilesystemProc
My code looks something like this:
typedef struct {
FILE* dbFile;
/*...*/
} FSBackend;
void createFS(const char* dbFile)
{
FSBackend* fsback = (FSBackend*)malloc(sizeof(FSBackend));
initDb(fsback,dbFile);
Tcl_Filesystem tfs;
tfs.typeName="Db Fs";
tfs.structureLength = sizeof(Tcl_Filesystem);
tfs.version = TCL_FILESYSTEM_VERSION_1;
tfs.pathInFilesystemProc = inFsProc;
/*...*/
Tcl_FSRegister((void*),tfs);
}
int inFsProc(Tcl_Obj* pathPtr,ClientData* cd)
{
/* How do I get my FSBackend struct here */
FSBackend* bk = /* ? */
int len;
const char* searchPath = Tcl_GetStringFromObj(pathPtr,&len);
char* foundPath = findFileInDb(searchPath,bk);
if (foundPath == 0) {
return -1;
}
cd = buildInternalRep(foundPath,bk);
return TCL_OK;
}
/**
...
*/
int main()
{
createFS("db1.db");
createFS("db2.db");
}
How do I, in inFsProc get back the struct I passed into Tcl_FSRegister?
The Tcl_FSData function says it can get it but I would then need to get a Tcl_Filesystem pointer
That's a weird one. The clientData handle there is not used to specify a mount point, but rather a separate capability of the filesystem type. Tcl's internal use of Tcl_FSRegister doesn't use it at all. The code which is as close as anything to a canonical use of it is the tclvfs package.
https://github.com/tcl-mirror/tclvfs/blob/master/generic/vfs.c#L385 shows us the use:
static void
Vfs_RegisterWithInterp(interp)
Tcl_Interp *interp;
{
ClientData vfsAlreadyRegistered;
/*
* We need to know if the interpreter is deleted, so we can
* remove all interp-specific mounts.
*/
Tcl_SetAssocData(interp, "vfs::inUse", (Tcl_InterpDeleteProc*)
Vfs_UnregisterWithInterp, (ClientData) 1);
/*
* Perform one-off registering of our filesystem if that
* has not happened before.
*/
vfsAlreadyRegistered = Tcl_FSData(&vfsFilesystem);
if (vfsAlreadyRegistered == NULL) {
Tcl_FSRegister((ClientData)1, &vfsFilesystem);
Tcl_CreateExitHandler(VfsExitProc, (ClientData)NULL);
Tcl_CreateThreadExitHandler(VfsThreadExitProc, NULL);
}
}
As you can see, the clientData there is really just being used as a marker so the code knows whether to do one-time initialisation.
To discover what the mount mapping is, you'll need to keep internal structures. You're strongly recommended to make the Tcl_Filesystem structure instance itself be global (or rather static at file scope) in your code.
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.
static struct dll_wifi_state **dll_states;
enum dll_type {
DLL_UNSUPPORTED,
DLL_ETHERNET,
DLL_WIFI
};
struct dll_state {
enum dll_type type;
union {
struct dll_eth_state *ethernet;
struct dll_wifi_state *wifi;
} data;
};
static struct dll_state *dll_states = NULL;
struct dll_wifi_state {
int link;
// A pointer to the function that is called to pass data up to the next layer.
up_from_dll_fn_ty nl_callback;
bool is_ds;
};
This is the method whose pointer is being passed in the dll_wifi_state struct.
static void up_from_dll(int link, const char *data, size_t length)
{
//some code here
}
In other file, I am calling this method
void reboot_accesspoint()
{
// We require each node to have a different stream of random numbers.
CNET_srand(nodeinfo.time_of_day.sec + nodeinfo.nodenumber);
// Provide the required event handlers.
CHECK(CNET_set_handler(EV_PHYSICALREADY, physical_ready, 0));
// Prepare to talk via our wireless connection.
CHECK(CNET_set_wlan_model(my_WLAN_model));
// Setup our data link layer instances.
dll_states = calloc(nodeinfo.nlinks + 1, sizeof(struct dll_state));
for (int link = 0; link <= nodeinfo.nlinks; ++link) {
switch (linkinfo[link].linktype) {
case LT_LOOPBACK:
dll_states[link].type = DLL_UNSUPPORTED;
break;
case LT_WAN:
dll_states[link].type = DLL_UNSUPPORTED;
break;
case LT_LAN:
dll_states[link].type = DLL_ETHERNET;
dll_states[link].data.ethernet = dll_eth_new_state(link, up_from_dll);
break;
case LT_WLAN:
dll_states[link].type = DLL_WIFI;
dll_states[link].data.wifi = dll_wifi_new_state(link,
up_from_dll,
true /* is_ds */);
break;
}
}
// printf("reboot_accesspoint() complete.\n");
}
It works fine like this, but I want to add another argument i.e. up_from_dll((int link, const char *data, size_t length, int seq). And as soon as I add this argument, following error starts coming up
ap.c:153: warning: passing argument 2 of ‘dll_wifi_new_state’ from incompatible pointer type
Is there a way of adding another argument to that method without getting error ??? I am really bad with pointers :(
Any help would be much appreciated.
Line 153 :
dll_states[link].data.wifi = dll_wifi_new_state(link,
up_from_dll,
true /* is_ds */);
And method
struct dll_wifi_state *dll_wifi_new_state(int link,
up_from_dll_fn_ty callback,
bool is_ds)
{
// Ensure that the given link exists and is a WLAN link.
if (link > nodeinfo.nlinks || linkinfo[link].linktype != LT_WLAN)
return NULL;
// Allocate memory for the state.
struct dll_wifi_state *state = calloc(1, sizeof(struct dll_wifi_state));
// Check whether or not the allocation was successful.
if (state == NULL)
return NULL;
// Initialize the members of the structure.
state->link = link;
state->nl_callback = callback;
state->is_ds = is_ds;
return state;
}
I haven't changed anything else apart from adding the new parameter to up_from_dll.
The second parameter to dll_wifi_new_state is up_from_dll_fn_ty callback.
It's not in your code listing right now, but up_from_dll_fn_ty is a typedef saying that the up_from_dll_fn_ty is a function pointer with specific parameters (which don't include int seq)
When you updated up_from_dll with different parameters, it no longer matches the type specified by up_from_dll_fn_ty and expected as the second parameter for dll_wifi_new_state. You'll need to add the parameter to up_from_dll_fn_ty and you should be good.
If you post the definition of up_from_dll_fn_ty, it would make the question have all the information and allow me to help you more if you still need it.
You're looking for something like:
typedef void (*up_from_dll_fn_ty)(int link, const char *data, size_t length);
and change it to
typedef void (*up_from_dll_fn_ty)(int link, const char *data, size_t length, int seq);
Here's a link to a question that has good information about creating typedefs for function pointers:
Understanding typedefs for function pointers in C
I have following query:
THis is my structure in some .h file
typedef struct
{
recUEInfo_t *recUEInfoPtr_t;
Int32 frameID;
Int32 slotIndx;
Int32 symNumber;
} recControlList;
If I do recControlList recControlListPtr; I can pass address to caller function
and collect it as a pointer in the definition
Fun(recControlListPtr);/* caller*/
and void Fun(*recControlListPtr);/* actual func*/
But if i do recControlList *recControlListPtr; then what should I do to
get the correct pointer?
Please help
I misunderstood who was the declarer and caller of the function initially, sorry about that, so if the function definition is:
Fun(recControlListPtr *precControlListPtr)
{
// Do stuff
}
You could call this way:
recControlListPtr rec1;
recContrlListPtr* prec2;
Fun(&rec1);
Fun(prec2);
Additional edit - My best guess at what I think you are trying to accomplish
typedef struct
{
recUEInfo_t *recUEInfoPtr_t;
int frameID;
int slotIndx;
int symNumber;
} recControlList;
void Fun(recControlList* pRecList)
{
ASSERT(pRecList != NULL);
int nFrameID = pRecList->frameID; // This line shows accessing the struct
// Do other stuff
}
recControlList rec1;
recControlList* pRec2 = &rec1;
Fun(&rec1);
Fun(pRec2);