是否可以创建一个可以在不同结构下运行的函数(在C中)?

时间:2016-06-14 15:01:26

标签: c function pointers struct unions

我正在寻找用C语言创建一个函数,它允许我接收不同的结构类型作为参数。 例如,如果我创建3个不同的结构

struct a{
    struct datatype0{
         char test1[10];
    }datatype;
    struct a *next;
};

struct b{
    struct datatype1{
        int test1;
        char test2[20];
        int test3;
    }datatype;
    struct b *next;
};

struct c{
    struct datatype2{
        char test1;
        char test2;
        float test3;
        int test4;
        int test5;
    }datatype;
    struct c *next;
};

我想创建一个函数,可以接收三个不同结构中的一个作为参数,所以我只能调用它来初始化第一种,或第二种或第三种结构:

void function("---")//<-- inside the brackets i need to insert a parameter that can be struct a, or struct b or struct c.
{
//here for example I can insert the initialize function that have to work with any struct.

}

我尝试使用union,但我看到我必须为每种结构重新创建初始化函数...我尝试使用void指针,但我需要在函数内部强制转换,我需要创建为每种结构初始化函数... 任何想法??

3 个答案:

答案 0 :(得分:1)

它的长短是:尽可能避免这样做,但要知道你可以将不同的结构传递给单个函数,如果你真的需要的话。

可能最简单的方法是创建一个包装器结构,它包含2个成员:一个union,以及一个标志,让你知道传递了哪个结构。

typedef enum {
    A,
    B,
    C
} struct_type;

struct _wrapper {
    union {
        struct a A;
        struct b B;
        struct c C;
    };
    struct_type flag;
};

void my_function(struct _wrapper *data)
{
    switch (data->flag)
    {
        case A:
            struct a val = data.A;
            //do stuff with A
            break;
        case B:
            struct b val = data.B;
            break;
        case C:
            struct c val = data.C;
            //...
            break;
    }
}

另一种选择,虽然它被认为是不好的做法,并且你最后会后悔的是依赖于任何结构的第一个成员的偏移量保证为0的事实。可以将指向任何结构的指针强制转换为指向其第一个成员的指针。如果所有结构的第一个成员兼容,您可以依赖它( 风险自负 )。
利用此方法的一种方法是将函数指针设置为第一个成员,或者将枚举字段设置为可用作标识结构的标志:

struct a {
    void (*common_member)();//
    /** other members **/
};
struct b {
    void (*common_member)();//needn't be the same name though
    /** other members **/
};

然后:

void my_func(void *data)
{//void pointer
    ((void (*)(void *))data)(data);//cast void *data to function pointer, and pass itself as an argument
}

这可以起作用,如果结构被正确初始化,并且成员指向正确的功能,但是如果要真的依赖那么太多了。

使用枚举作为第一个成员的风险稍低,但仍然不建议使用。它是函数指针和联合方法的组合

void my_func(void *data)
{
    //cast void * to struct_type *, dereference AFTER the cast
    //because you can't dereference a void *
    switch(*((struct_type *) data))
    {
        case A: /* stuff */ break;
        case B: /* struct b */ break;
    }
}

总而言之,使用第一种方法。不要使用函数指针成员,并确认第三种方法是什么:true,你不需要一个包装器结构,但它并不比原来的方法(函数指针)安全得多,并且不比第一种方法(带工会)更详细。

底线:结构和联合是可行的方式

答案 1 :(得分:0)

部分原因是有效的。但是,例如,如果我想创建一个像:

这样的函数
typedef union elemento{
    struct a A;
    struct b B;
    struct c C;
}elemento;

void inserimentoOrdinato(elemento dausare){
    struct b prova;
    prova.datatype.test1 = 3;
    strcpy(prova.datatype.test2,"TESTA");
    prova.datatype.test3 = 200;
    prova.next = (struct a*)malloc(sizeof(struct a));
    dausare.B = prova;
}

我需要使用&#34; dausare.B&#34;或&#34; dausare.C&#34;对于不同种类的结构。它并不知道联盟的哪个部分必须使用它。我操纵了吗?谢谢!

答案 2 :(得分:0)

答案是通用编程和函数指针:

** void *可以是指向任何结构的指针

声明部分:

typedef void *Initializer(void* obj);//since every struct has its own fields to initialize

void function(void * obj, Initializer init)
{
    init(obj);
}

用法:

void InitA(void* a_void)
{
    struct a* a  = (struct a*) a_void;
    //init a feilds
    a->next = NULL;
}

void InitB(void* b_void)
{
    struct b* b  = (struct b*) b_void;
    //init b feilds
    b->next = NULL;
}

void InitC(void* c_void)
{
    struct c* c  = (struct c*) c_void;
    //init a feilds
    c->next = NULL;
}

int main()
{
    struct a a;
    struct b b;
    struct c c;

    Init(&a,InitA);
    Init(&b,InitB);
    Init(&c, initC);

    return 0;
}

***请记住,如果每个结构都有相同的字段要初始化,则不必为每个结构构建不同的函数。