我有如下功能。它需要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 */
}
}
我正在寻找一种可以处理这种情况的解决方案,避免重复代码。
答案 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指针中返回值,以便调用函数可以使用它。