Page 1 of 2
How do you return a function from a macro!?(in C)
Posted: Thu Dec 28, 2006 9:48 pm
by earlz
I'm attempting to make a macro and well I need to know how you would return a function from a macro like this:
Code: Select all
#define add_me(a,b) return a+b
if(42==add_me(40,2)) //and that translate to if(42==42)
Re: How do you return a function from a macro!?(in C)
Posted: Thu Dec 28, 2006 10:42 pm
by Brendan
Hi,
hckr83 wrote:I'm attempting to make a macro and well I need to know how you would return a function from a macro like this:
Code: Select all
#define add_me(a,b) return a+b
if(42==add_me(40,2)) //and that translate to if(42==42)
Macros in C do text substitution, so the above would actually be translated into:
Try something like:
Which would be translated into:
Cheers,
Brendan
Posted: Thu Dec 28, 2006 10:43 pm
by earlz
well I can't do that, as their are complicated things in it like for loops(that was just an example) so..what?
edit:
this is my actual code but I wish I could make it easier to use(or at least no temp variable[tmp_int])
Code: Select all
#define linked_GetObject(pointer,number_wanted,name_of_next,name_of_prev,tmp_int)\
tmp=number_wanted;\
if(number_wanted>0){\
for(;tmp_int!=0;tmp_int--){\
pointer=pointer->name_of_next; \
}\
}else{\
if(number_wanted!=0){\
for(;tmp_int!=0;tmp_int++){\
pointer=pointer->name_of_prev; \
}\
}\
}
Posted: Fri Dec 29, 2006 5:05 am
by Ready4Dis
Why are you using a macro for something that big? There are better ways to do that, like with a function, or inlined function if you really want it inlined. Are you stuck in C or can you use C++ for templates (just incase you need this for multiple types). If it's in C, all objects in your linked list should be very similar in construct, in which case, you can treat them all the same (pass the pointer to the linked list data section, rather than the actual data structure, or ensure that all objects that are in linked lists have the linked list data as the first data in the object, then you can cast them all to the linked list to pass them to a generic function, and cast back to the type you are working with on return. If you are using C++, templates are the way to go. If you wanted to use what you have though, the easiest way would be to pass the variable that you want to have set, instead of setting it equal to... for example:
Code: Select all
#define linked_GetObject(pointer,number_wanted,name_of_next,name_of_prev,tmp_int,ReturnValue)\
tmp=number_wanted;\
if(number_wanted>0){\
for(;tmp_int!=0;tmp_int--){\
pointer=pointer->name_of_next; \
}\
}else{\
if(number_wanted!=0){\
for(;tmp_int!=0;tmp_int++){\
pointer=pointer->name_of_prev; \
}\
}\
ReturnValue = pointer;
} else ReturnValue = NULL; //Just incase ;)
This fixes your issue and you don't need to return anything, there really isn't a better way to do what you are trying than just passing it in like that, or changing it to a function (either inlined or regular).
Posted: Fri Dec 29, 2006 8:59 am
by Solar
As Brendan stated, macros do text substitution only. You could write a macro that evaluates to a pointer value (by tricky use of the comma operator, for example), but in my experience, too tricky / big macros solve one problem, but create a handful other ones.
I'd also suggest a function-based solution.
Posted: Fri Dec 29, 2006 11:55 am
by earlz
I really don't want to use macro's anyway.. my other best idea is maybe haveing something like
void *linked_GetObject(void *_struct,void *whereis_prev,void *whereis_next,unsigned int number);
and jsut subtract whereis_prev and next with _struct to get the offset at which they are, then it's pretty simple from there..
edit:
this is what I got now..
it doesn't work for some reason though..
edit2:
ok now it's fixed, works perfect!
Code: Select all
void *linked_GetObject(void *data,void *prev,void *next,signed int number){
signed int tmp;
unsigned int diff_next=(next-data);
unsigned int diff_prev=(prev-data);
void **ptr;
tmp=number;
if(number==0){return data;}
if(number>0){
for(;tmp!=0;tmp--){
data=data+diff_next;
ptr=data;
data=*ptr;
}
}else{ //tmp is less than 0, or negative
for(;tmp!=0;tmp++){
data=data+diff_prev;
ptr=data;
data=*ptr; //C doesn't allow you to jsut specify void **, have to make a whole new variable!
}
}
return data;
}
//to do this just do next_object=linked_GetObject(current_object,¤t_object->next,¤t_object->prev,1);
//to you can even go backwards! just do -1 or -2.. prev is only used if you do negative
Posted: Fri Dec 29, 2006 4:02 pm
by Ready4Dis
Code: Select all
typedef struct
{
void *prev;
void *next;
} linked_object;
typedef struct
{
linked_object link;
unsigned int blah;
} test_object;
//Why were you passing next/prev, they are in there already!
void *linked_GetObject2(linked_object *start,signed int number)
{
unsigned int tmp;
linked_object *ptrCur;
ptrCur = start;
tmp=number;
if(number==0){return start;}
if(number>0){
for(;tmp!=0;tmp--){
ptrCur=ptrCur->next;
}
}else{ //tmp is less than 0, or negative
for(;tmp!=0;tmp++){
ptrCur=ptrCur->prev;
}
}
return ptrCur;
}
int main()
{
test_object *blah;
test_object *ptr;
test_object *again;
test_object *now;
test_object *bah;
test_object *test;
signed int tmp;
blah=malloc(sizeof(test_object));
ptr=malloc(sizeof(test_object));
again=malloc(sizeof(test_object));
now=malloc(sizeof(test_object));
bah=malloc(sizeof(test_object));
blah->prev=NULL;
blah->next=ptr;
ptr->prev=blah;
ptr->next=again;
again->prev=ptr;
again->next=now;
now->prev=again;
now->next=bah;
bah->prev=now;
bah->next=NULL;
test=ptr;
test=linked_GetObject2(&test.link,2); //here!
if(test==now){return 0;}else{return 1;} //this should be 0
}
This is hopefully a bit more readable!
Edit:
Ok, don't use your version please, just checked your edit, and there are huge errors in there that will come back and bite you later. Firstly, you are taking the difference between prev and the passed pointer... and next and passed pointer... then in the loop adding this. That assumes that ALL of the objects that are linked are the exact same distance apart from each other, which, when allocating them dynamically is anywhere near gaurranteed! Use a version similar to what I provided, it is much more consistant, and actually less code, and less chance of bugs, although you should check for NULL inside those for loops, otherwise you can come up with problems if you try to go past the end of the list (since it doesn't loop around).
Posted: Fri Dec 29, 2006 4:09 pm
by earlz
thanks, but I want to be able to use this on any struct(not just ones I make..)
Posted: Fri Dec 29, 2006 4:19 pm
by Ready4Dis
hckr83 wrote:thanks, but I want to be able to use this on any struct(not just ones I make..)
Mine works with ANY struct that has linked_object as the first element in it. There has to be some consistancy in order for it to work, they have to have prev/next in the same location, otherwise how will the function know where they are located. You could use templates if you aren't against using C++ in your kernel, that is a much prettier solution, but that won't compile in a C compiler
. Here is an example with my code using more than one type...
Code: Select all
typedef struct
{
void *prev;
void *next;
} linked_object;
typedef struct
{
linked_object link;
unsigned int blah;
} test_object;
typedef struct
{
linked_object link;
unsigned char Stuff[10];
} test_object2;
//Why were you passing next/prev, they are in there already!
void *linked_GetObject2(linked_object *start,signed int number)
{
unsigned int tmp;
linked_object *ptrCur;
ptrCur = start;
tmp=number;
if(number==0){return start;}
if(number>0){
for(;tmp!=0;tmp--){
ptrCur=ptrCur->next;
}
}else{ //tmp is less than 0, or negative
for(;tmp!=0;tmp++){
ptrCur=ptrCur->prev;
}
}
return ptrCur;
}
int main()
{
test_object *blah;
test_object *ptr;
test_object2 *again;
test_object *now;
test_object *bah;
test_object2 *test;
signed int tmp;
blah=malloc(sizeof(test_object));
ptr=malloc(sizeof(test_object));
again=malloc(sizeof(test_object2));
now=malloc(sizeof(test_object));
bah=malloc(sizeof(test_object));
blah->prev=NULL;
blah->next=ptr;
ptr->prev=blah;
ptr->next=again;
again->prev=ptr;
again->next=now;
now->prev=again;
now->next=bah;
bah->prev=now;
bah->next=NULL;
test2=(test_object2*)ptr; //Lets cast, because it's another type!
test=linked_GetObject2(&test.link,2); //here!
if(test==now){return 0;}else{return 1;} //this should be 0
}
I made again the other type, so you can see that you can even link mutliple object types in a single list. Normally you would seperate different object types into multiple lists, but it can handle any object that has linked_object as it's first variable.
Posted: Fri Dec 29, 2006 4:25 pm
by earlz
your method won't work if linked_object are in different spots though..
Posted: Fri Dec 29, 2006 5:02 pm
by Ready4Dis
No, it must be the first element of the struct. The only other easy method is using templates, let me know if that's a route you are interested in. There HAS to be a way to tell where inside the struct the info is located, otherwise there is no way to do it. Using a macro repeats that code each and every time it runs, which would make your code very big, templates will create that code for each type that you call it with, and the method I provided and creates that code the one time. Those are pretty much all your options, there really isn't a good way to do that in a macro, so that really only leaves 3 options, one I forgot to mention, might be something you'd be inerested in. Option 1, the method I provided, option 2, templates, and option 3... a linkd list of void*'s, with each void* pointing to any type of data you wanted to supply... here is an exampl of how that would work:
Code: Select all
typedef struct
{
void *prev;
void *next;
void *data;
} linked_object;
typedef struct
{
unsigned int blah;
} test_object;
typedef struct
{
unsigned char Stuff[10];
} test_object2;
//Why were you passing next/prev, they are in there already!
void *linked_GetObject(linked_object *start,signed int number)
{
unsigned int tmp;
linked_object *ptrCur;
ptrCur = start;
tmp=number;
if(number==0){return start;}
if(number>0){
for(;tmp!=0;tmp--){
ptrCur=ptrCur->next;
}
}else{ //tmp is less than 0, or negative
for(;tmp!=0;tmp++){
ptrCur=ptrCur->prev;
}
}
return ptrCur->data; //return the object, not the list item!
}
linked_object *head=NULL, *tail = NULL;
void AddToList(void *data_ptr)
{
linked_object *ptrNew;
if (tail == NULL) //No list yet!
{
head = malloc(sizeof(linked_object));
tail = head;
head->prev = 0;
head->next = 0;
head->data = data_ptr;
}
else //Ok, we already have something!
{
ptrNew = malloc(sizeof(linked_object));
ptrNew->prev = tail;
ptrNew->next = NULL;
tail->next = ptrNew;
tail = ptrNew;
ptrNew->data = data_ptr;
}
}
int main()
{
test_object obj1;
test_object obj2;
test_object2 obj3;
test_object2 obj4;
test_object2 *ptr;
AddToList(&obj1);
AddToList(&obj2);
AddToList(&obj3);
AddToList(&obj4);
ptr = linked_GetObject(obj1,2);
}
Ok, this hasn't been tested, but gives you an idea on what i'm talking about. The data is treated as such, data, it knows nothing about pointing to anything, or being in a list. The linked_object struct contains a pointer to prev/next and the data which it is holding. You can use this with any data type irregardless. Hope this helps explain some of the weirdness of C poitners and linked lists!
Posted: Fri Dec 29, 2006 5:08 pm
by earlz
how would you do it with templates, and also, would you be able to use templates in normal C code?(like call the function made in c++ or something?)
Posted: Fri Dec 29, 2006 5:14 pm
by Ready4Dis
hckr83 wrote:how would you do it with templates, and also, would you be able to use templates in normal C code?(like call the function made in c++ or something?)
That depends on your compiler, if it supports templates or not. If it does, it doesn't require any extra library functions specific to your OS or anything like that.
Templates goes something like this:
Code: Select all
template <T>
T *linked_GetObject(T *ptrT, signed int number)
{
unsigned int tmp;
T *ptrCur;
ptrCur = ptrT;
tmp=number;
if(number==0){return ptrCur;}
if(number>0){
for(;tmp!=0;tmp--){
ptrCur=ptrCur->next;
}
}else{ //tmp is less than 0, or negative
for(;tmp!=0;tmp--){
ptrCur=ptrCur->prev;
}
}
return ptrCur; //return the object, not the list item!
}
Now you can call this with any structure or class that has prev and next as members, no matter where they are located! Also, no casting required because it generates this function for every type that you pass it! Much nicer looking, but if you use it with a lot of types, will bloat your code pretty bad too depending on how many functions you create, and types you use. Also, you cannot mix and match different types in one list!
Posted: Fri Dec 29, 2006 5:35 pm
by Ready4Dis
Almost forgot, one more neat thing on templates, you can use them for classes as well, if you are into the C++ thing at all...
Code: Select all
template <T>
class GenericData
{
public:
T Data;
GenericData* next;
GenericData* prev;
};
template <T>
class GenericList
{
public:
GenericData<T> *Head, *Tail;
public:
GenericList(void)
{
Head = Tail = 0;
};
~GenericList(void)
{
ClearList();
};
void AddToList(T Data)
{
GenericData<T> *ptrNew;
if (Head == 0) //Nothing yet?
{
Head = malloc(sizeof(GenericData<T>)); //Avoid new operator
Tail = Head;
Head->Prev = Head->Next = 0;
}
else
{
ptrNew = malloc(sizeof(GenericData<T>)); //Avoid new operator
ptrNew->Prev = Tail;
ptrNew->Next = 0;
Tail->Next = ptrNew;
Tail = ptrNew;
}
Tail->Data = Data;
}
T GetByIndex(int Index) //Get an element based on it's index!
{
GenericData<T> *ptrCur = Head;
while (Index-- && ptrCur) //Make sure ptrCur != NULL!!!!
ptrCur = ptrCur->Next;
return ptrCur->Data;
}
};
typdef struct
{
int TestNum;
float x,y;
} object_type1;
GenericList<object_type1*> Object1List; //store a list of pointers to this type!
int main(void)
{
object_type1 *ptrObj1, *ptrObj2, *ptrObj3, *ptrRet;
ptrObj1 = malloc(sizeof(object_type1));
ptrObj2 = malloc(sizeof(object_type1));
ptrObj3 = malloc(sizeof(object_type1));
Object1List.AddToList(ptrObj1);
Object1List.AddToList(ptrObj2);
Object1List.AddToList(ptrObj3);
ptrRet = GetByIndex(1); //Returns ptrObj2!
}
The beauty of this type of design is that it can support any type, even built in types! This is very similar to how the STL list works, so you might want to look into it. I have a fully developed version of this that I use for my game programming (do't use it in my OS dev, i am sticking to C only), if you want it, when I go home tomorrow I can send you the file, it works very much the same, and I have 2 versions, one a linked list, and the other is a dynamic array that can be accessed via the [] just like a normal array, but you can dynamically change its size. It also has a delete function that will call delete on all the pointers while erasing the list, so I don't have to call free on each and every object, and then remove them from the list, it does it all at once (only use it if you are uing an array of pointers, it can be used for any type that supports the = operator).
Posted: Sun Dec 31, 2006 7:20 am
by Solar
I just skimmed over the last few posts, but you might want to check out the offsetof macro from the standard library. Used in a macro, it would enable you to access common members in your structs regardless of their position - and give you a compiler warning if used on a struct that doesn't have that member.