基于版本参数的强制转换函数参数,以避免重复代码

时间:2013-10-18 06:11:37

标签: c struct

我有如下功能。它需要2个参数。一个是指向结构的void指针,另一个是版本号。根据传递的版本,void指针需要被转换为2个几乎相似的结构。(一个有数组,另一个有指针)。

struct some_v0{
    char a;
    int some_array[200];
    char b;
}
struct some_v0{
    char a;
    int *some_array;
    char b;
}
void some_api(void * some_struct, int version){
    /* Depending on version the void pointer is cast to 2 different version of a struct*/
    /* This is followed by some common code which is similar for both version of struct(as array access and pointer access have similar code)*/
}

由于数组访问和指针访问都有类似的代码,因此两个版本之间的唯一区别是无效指针的转换。

我目前的方法如下。

void some_api(void * some_struct, int version){


    if(version == 0){
        struct some_v0 v0;
        v0= *(struct some_v0 *)some_struct;
        /* block of code which uses v0 */
    }
    if(version == 1){
        struct some_v1 v1;
        v1= *(struct some_v1 *)some_struct;
        /* block of code which uses v1 */
    }
}

上面使用的代码块类似,因为数组访问和指针访问类似。我想在上面的例子中避免重复的代码。任何帮助表示赞赏。我正在寻找一种可以帮助我避免重复代码的解决方案。

注意:我无法更改结构成员的定义顺序。我知道如果数组是结构定义中的最后一个元素,那么解决方案很简单。出于向后兼容性原因,我不允许更改struct元素的顺序。

编辑1:我还有一个类似的API,我需要填充输入结构并将其返回给调用函数。

void some_api(void * some_struct, int version){


    if(version == 0){
        struct some_v0 *v0;
        v0= (struct some_v0 *)some_struct;
        /* block of code which uses v0  fill v0*/
    }
    if(version == 1){
        struct some_v1 *v1;
        v1= (struct some_v1 *)some_struct;
        /* block of code which uses v1. Fill v1 */
    }
}

我正在寻找一种可以处理这种情况的解决方案,避免重复代码。

2 个答案:

答案 0 :(得分:4)

至于你的一般性问题,你实际上可以使用some_v1结构访问some_v0结构,如果唯一的区别是v0中的数组与v1中的指针。

struct some_v1 v1;

if(version == 0){
    v1.a = ((struct some_v0 *) some_struct)->a;
    v1.some_array = ((struct some_v0 *) some_struct)->some_array;
    v1.b = ((struct some_v0 *) some_struct)->b;
} else if (version == 1)
    v1 = *(struct some_v1 *) some_struct;
}

在此之后,结构v1可以用于两个版本。


如果您以后添加some_v2结构只会将成员添加到some_v1结构中,那么您可以使用相同的技术。只需记住在复制v1结构后在v2结构中设置字段。

例如

struct some_v2
{
    char a;
    int *some_array;
    char b;
    int c;  /* New field in v2 */
};

然后你可以做

struct some_v2 v2;

if(version == 0){
    v2.a = ((struct some_v0 *) some_struct)->a;
    v2.some_array = ((struct some_v0 *) some_struct)->some_array;
    v2.b = ((struct some_v0 *) some_struct)->b;
    v2.c = 0;
} else if (version == 1)
    memcpy(&v2, some_struct, sizeof(struct some_v1));
    v2.c = 0;
} else {
    v2 = *(struct some_v2 *) some_struct;
}

我建议将所有这些放在一个单独的功能中,以便在需要时轻松重复使用。


在更新问题之后,如果你想使用指针,你可以做这样的事情(考虑原始只有两个版本的结构):

struct some_v1 v1_np;  /* Non-pointer structure */
struct some_v1 *v1;  /* the pointer we will work with */

if (version == 0) {
    v1_np.a = ((struct some_v0 *) some_struct)->a;
    v1_np.some_array = ((struct some_v0 *) some_struct)->some_array;
    v1_np.b = ((struct some_v0 *) some_struct)->b;
    v1 = &v1_np;
} else if (version == 1) {
    v1 = (struct some_v1 *) some_struct;
}

如图所示,这与原始版本非常相似。这里的问题是v0和v1结构在任何方面都不兼容(尝试检查两个结构的sizeof并且你可能理解为什么),这就是为什么你需要一个你可以制作的临时v1_np结构的原因v1指向。

答案 1 :(得分:1)

我解决这个问题的方法。

我没有使用2个版本的struct,而是在some_v0中引入了一个新的struct成员,如下所示。 注意:我不是在这里改变struct成员的顺序。

struct some_v0{
    char a;
    int some_array[200];
    char b;
    int *some_array_v1;
};

API函数可以实现为:

void some_api(void * some_struct, int version){
    struct *some_v0 v0= (some_v0 *)ptr;
    int *ptr; /*pointer we will be working on*/
    if (version == 0) {
         ptr=some_v0->some_array;
    } else if (version == 1) {
         ptr=some_v0->some_array_v1;
    }
/*Common code block which uses ptr wherever some_arry is used. All other members can be dereferenced using v0*/
}

这可以避免重复代码并处理api版本。这也需要在struct指针中返回值,以便调用函数可以使用它。