0

我有一个功能如下。它需要 2 个参数。一个是指向结构的空指针,另一个是版本号。根据传递的版本,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 指针的强制转换。

我目前的方法如下。

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 */
    }
}

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

4

2 回答 2

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指出的临时结构。

于 2013-10-18T06:15:19.523 回答
1

我解决这个问题的方式。

我没有使用 2 个版本的 struct,而是在 some_v0 中引入了一个新的 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 版本。这还负责返回结构指针中的值,以便调用函数可以使用它。

于 2013-10-20T10:26:20.260 回答