I have a type defined like this:
struct DynTab_s {
int object_count;
//other fields
void *data;
};
typedef struct DynTab_s *Dyntab_t; //note that type I use is pointer to struct
I have a storage utility that I can user to store and retrieve them. I've chosen to support int, double and pointer type. I have a function to retrieve the int and double values by key:
int MyHashtableGet(MyHashtable_t Hashtable, void *Key, void *Value)
{
void *Row = NULL;
int RetValue = -1;
MakeRow(Hashtable, Key, NULL, &Row);
if (!MyStoreSelect(Hashtable->TableId, Row))
{
switch (Hashtable->ValueType)
{
case MY_HASHTABLE_TYPE_INT:
*(int *)Value = *(int *)((char *)Row + Hashtable->KeySize);
break;
case MY_HASHTABLE_TYPE_POINTER:
//after row below I can see the DynTab_t in the item when I cast it
Value = *(void **)*(int **)((char *)Row + Hashtable->KeySize);
break;
}
}
MyFree(Row);
return RetValue;
}
that work for int. But not for pointer when I try to get Dyntab_t. This works if I use function
void *MyHashtableGetPointer(MyHashtable_t Hashtable, void *Key)
{
void *Row = NULL;
void *RetValue = NULL;
MakeRow(Hashtable, Key, NULL, &Row);
if (!MyStoreSelect(Hashtable->TableId, Row))
RetValue = *(void **)*(int **)((char *)Row + Hashtable->KeySize);
MyFree(Row);
return RetValue;
}
when I call it with:
int Key = 1;
DynTab_t MyTab;
MyTab = (DynTab_t)MyHashtableGetPointer(MyHashtable, &Key);
The question is can I at all use this MyHashtableGet to get DynTab_t item or does second parameter have to be void ** type? If yes, can you please provide the exact syntax to call and to MyHashtableGet in case of MY_HASHTABLE_TYPE_POINTER.
Thanks & BR -Matti
The question is can I at all use this MyHashtableGet to get DynTab_t item or does second parameter have to be void ** type?
The only difference (if you're storing the pointers like you store the int
values) would be that when retrieving an int
, you'd pass the address of an int
variable; and when retrieving a pointer, you'd pass the address of a pointer variable. A void *
can hold the address of anything (except functions sometimes) -- including other pointers. So the last parameter is fine as void *
, as long as you handle it appropriately elsewhere.
I'm not sure what you're doing in your function, though. If you store the pointers the same way as the int
s in your data structure, so that at the same level of indirection you'd have an int
for the integer type and a void *
for the pointer type, then why are they dereferenced to different levels?
case MY_HASHTABLE_TYPE_INT:
*(int *)Value = *(int *)((char *)Row + Hashtable->KeySize);
break;
In the above, it seems that ((char *)Row + Hashtable->KeySize)
gets you the pointer to whatever value you've stored, though of the wrong pointer type. Then the (int *)
casts to a pointer of your data's type ( int
in this case), which you then dereference and assign to what Value
points to.
case MY_HASHTABLE_TYPE_POINTER:
Value = *(void **)*(int **)((char *)Row + Hashtable->KeySize);
break;
But here, you cast to int **
, dereference, cast to void **
, then dereference again, and assign to Value
instead of what Value
points at? Isn't that one too many dereferences? Shouldn't you assign to the target of Value
rather than Value
? And why do you need to cast to int **
at all? I think it should be more like this:
case MY_HASHTABLE_TYPE_POINTER:
*(void **)Value = *(void **)((char *)Row + Hashtable->KeySize);
break;
Then, when calling to get an int:
...
int Val;
MyHashtableGet(Table, Key, &Val);
...and when calling to get a pointer:
...
void *Val;
MyHashtableGet(Table, Key, &Val);
Edit: This assumes one of two things, though: That the the variable you passed the address of in Value
is void *
, or that the variable you passed the address of is of a type that is internally represented the same way as void *
(often true, but not guaranteed). If you want to rely on the pointer type being converted on assignment (in case their representations differ), you could implement your MyHashtableGetPointer()
function as a wrapper for MyHashtableGet()
:
void *MyHashtableGetPointer(MyHashtable_t Hashtable, void *Key)
{
void *res = NULL;
MyHashtableGet(Hashtable, Key, &res);
return res;
}
It really depends on how you want to do it. You can do it using a reference (only in C++) or a pointer (C and C++):
void changeTheParamRef(struct myStruct &s)
{
myStruct other;
s = other; // or
s.something = other.something;
}
void changeTheParamPtr(struct myStruct *s)
{
myStruct other;
*s = other; // or
s->something = other.something;
}
void allocStruct(struct myStruct **s)
{
*s = malloc(sizeof(myStruct));
}
You don't need a pointer to a pointer unless you'd like to return or change a pointer instead of a value.
To call above samples:
myStruct s;
changeTheParamRef(s);
changeTheParamPtr(&s);
myStruct *p;
allocStruct(&p);
changeTheParamRef(*p);
changeTheParamPtr(p);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.