我可以从C函数中获取指向结构的指针作为参数吗?

时间:2011-11-25 14:37:32

标签: c pointers void-pointers

我有一个这样定义的类型:

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

我有一个存储实用程序,我可以用来存储和检索它们。我选择支持int,double和指针类型。我有一个函数来通过键检索int和double值:

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;
}

为int工作。但是当我试图获得Dyntab_t时,不是指针。如果我使用函数

,这是有效的
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;
}

当我打电话给:

int       Key = 1;
DynTab_t  MyTab;

MyTab = (DynTab_t)MyHashtableGetPointer(MyHashtable, &Key);

问题是我可以使用此MyHashtableGet来获取DynTab_t项目,还是第二个参数必须为void **类型?如果是,请在MY_HASHTABLE_TYPE_POINTER的情况下提供确切的语法和MyHashtableGet。

谢谢& BR -Matti

2 个答案:

答案 0 :(得分:1)

  

问题是我可以使用此MyHashtableGet来获取DynTab_t项目,还是第二个参数必须为void **类型?

唯一的区别(如果您存储指针,就像存储int值一样),那就是在检索int时,您会传递int的地址变量;并且在检索指针时,您将传递指针变量的地址。 void *可以保存任何地址(有时除了函数) - 包括其他指针。所以最后一个参数可以正常为void *,只要你在其他地方适当地处理它。

但是,我不确定你在功能方面做了什么。如果您以与数据结构中int相同的方式存储指针,那么在相同的间接级别,您将获得整数类型的intvoid *对于指针类型,那么为什么它们被解引用到不同的级别?

    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;
}

答案 1 :(得分:0)

这实际上取决于你想怎么做。您可以使用引用(仅在C ++中)或指针(C和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));
}

除非您想要返回或更改指针而不是值,否则不需要指向指针的指针。

调用以上样本:

myStruct s;
changeTheParamRef(s);
changeTheParamPtr(&s);

myStruct *p;
allocStruct(&p);
changeTheParamRef(*p);
changeTheParamPtr(p);