Вопрос в том, могу ли я вообще использовать этот MyHashtableGet для получения элемента DynTab_t или второй параметр должен иметь тип void **?
Единственное отличие (если вы хранитеуказатели, такие как вы храните значения int
), будут такими, что при извлечении int
вы передадите адрес переменной int
;и при получении указателя вы передадите адрес переменной указателя.void *
может содержать адрес чего угодно (кроме функций), включая другие указатели.Поэтому последний параметр подходит как void *
, если вы правильно его обрабатываете в другом месте.
Хотя я не уверен, что вы делаете в своей функции.Если вы храните указатели так же, как int
s в вашей структуре данных, так что на том же уровне косвенности у вас будет int
для целочисленного типа и void *
для типа указателя, тогдапочему они разыменовываются на разные уровни?
case MY_HASHTABLE_TYPE_INT:
*(int *)Value = *(int *)((char *)Row + Hashtable->KeySize);
break;
В приведенном выше примере кажется, что ((char *)Row + Hashtable->KeySize)
возвращает указатель на любое сохраненное вами значение, хотя и с неверным типом указателя.Затем (int *)
приводит к указателю типа ваших данных (int
в данном случае), который вы затем разыменовываете и присваиваете то, на что указывает Value
.
case MY_HASHTABLE_TYPE_POINTER:
Value = *(void **)*(int **)((char *)Row + Hashtable->KeySize);
break;
Но здесь вы бросаетена int **
, разыменование, приведение к void **
, затем разыменование снова и присвоение Value
вместо того, на что указывает Value
?Разве это не слишком много разыменований?Разве вы не должны назначить цели Value
, а не Value
?И зачем вообще нужно приводить к int **
?Я думаю, что это должно быть больше так:
case MY_HASHTABLE_TYPE_POINTER:
*(void **)Value = *(void **)((char *)Row + Hashtable->KeySize);
break;
Затем, при вызове для получения int:
...
int Val;
MyHashtableGet(Table, Key, &Val);
... и при вызове, чтобы получить указатель:
...
void *Val;
MyHashtableGet(Table, Key, &Val);
Редактировать: Это предполагает одну из двух вещей: что переменная, адрес которой вы передали в Value
, равна void *
или переменная, которой вы передали адресимеет тип, который внутренне представлен так же, как void *
(часто это правда, но не гарантируется).Если вы хотите полагаться на тип указателя, преобразуемый при присваивании (в случае, если их представления различаются), вы можете реализовать свою функцию MyHashtableGetPointer()
в качестве оболочки для MyHashtableGet()
:
void *MyHashtableGetPointer(MyHashtable_t Hashtable, void *Key)
{
void *res = NULL;
MyHashtableGet(Hashtable, Key, &res);
return res;
}