提问人:arivero 提问时间:1/13/2022 最后编辑:arivero 更新时间:1/14/2022 访问量:94
管理类似的结构,一个使用数组,另一个使用指针
manage similar structs, one with arrays, the other with pointers
问:
我有一些包含数组的结构
struct mystruct_withArrays {
int foo;
int bar[MaxN];
int baz[MaxM];
}
以及它们与指针的等价物
struct mystruct_withPointers {
int foo;
int *bar;
int *baz;
}
我想避免双重定义。这是我想做一些东西作为模板
#define myStruct(M,N)
...
这样可以生成数组结构并生成带有指针的结构。myStruct(MaxM,MaxN)
myStruct(,)
此外,我当然想对多个结构执行相同的技术,并自动映射从数组到指针。最终用例如下
#include "mystructs.h"
//globals, for huge space usage
struct myStructA(1000,10000) hugeA;
struct myStructB(1024*1024) * hugeB;
void main(){
struct myStructA(,) smallA;
struct myStructB() smallB;
mapStruct(hugeA,smallA) //this is a macro
mapStruct(hugeB,smallB) //this is a macro
doSomething(smallA);
doSomethingMore(smallA,smallB);
doSomethingDetailed(smallB.qux);
}
哪里是明显的映射,等等。扩展后的代码为:mapStruct(hugeA, smallA)
smallA.bar = hugeA.bar
struct myStructA(1000,10000) hugeA;
struct myStructB(1024*1024) hugeB;
struct mystructA_withArrays {
int foo;
int bar[1000];
int baz[10000];
} hugeA;
struct mystructB_withArrays * {
int qux[1048576];
int quux[1048576];
} hugeB;
void main(){
struct mystructA_withPointers {
int foo;
int * bar;
int * baz;
} smallA;
struct mystructB_withArrays {
int * qux;
int * quxx;
} smallB;
smallA.bar=hugeA.bar;
smallA.baz=hugeA.baz;
smallB.qux=hugeB.qux;
smallB.quxx=hugeB.quxx;
doSomething(smallA);
doSomethingMore(smallA,smallB);
doSomethingDetailed(smallB.qux);
}
正如你所看到的,一般的想法是,一些变量被分配到堆栈之外,但仍然不使用 malloc,只是将它们声明为全局变量。即使在某些用例中,它们也是来自链接共享对象的外部全局变量。
编辑: 关于内存性能,要确定 malloc 结构体是比全局结构体好还是差并不容易。它还取决于编译器的标志 -mcmodel
答:
1赞
Bodo
1/13/2022
#1
创建多个类似结构的可能解决方案可能是使用 X 宏。
(与维基百科页面不同,我将宏作为参数传递,而不是重新定义宏。X
我稍微编辑了代码,将数组的赋值添加到相应的指针。我使用可变参数宏来允许省略参数列表中的变量名称。这是为了展示概念,可能还有改进的余地。
示例文件macro.c
#define LIST_OF_ARRAY_FIELDS_1(X, ...) \
X(int, bar, MaxN, __VA_ARGS__) \
X(int, baz, MaxM, __VA_ARGS__)
#define LIST_OF_ARRAY_FIELDS_2(X, ...) \
X(char, bla1, MaxK, __VA_ARGS__) \
X(char, bla2, MaxL, __VA_ARGS__)
#define CREATE_ARRAY_FIELD(type, name, size, ...) \
type name[size];
#define CREATE_POINTER_FIELD(type, name, size, ...) \
type *name;
struct mystruct_withArrays {
int foo;
LIST_OF_ARRAY_FIELDS_1(CREATE_ARRAY_FIELD)
}
struct mystruct_withPointers {
int foo;
LIST_OF_ARRAY_FIELDS_1(CREATE_POINTER_FIELD)
}
struct otherstruct_withArrays {
int foo;
LIST_OF_ARRAY_FIELDS_2(CREATE_ARRAY_FIELD)
}
struct otherstruct_withPointers {
int foo;
LIST_OF_ARRAY_FIELDS_2(CREATE_POINTER_FIELD)
}
mystruct_withArrays hugeA;
mystruct_withPointers smallA;
otherstruct_withArrays hugeB;
otherstruct_withPointers smallB;
#define ASSIGN_POINTERS(type, name, size, dest, src) \
dest.name = src.name;
LIST_OF_ARRAY_FIELDS_1(ASSIGN_POINTERS, smallA, hugeA)
LIST_OF_ARRAY_FIELDS_2(ASSIGN_POINTERS, smallB, hugeB)
结果:
$ gcc -E macro.c
# 1 "macro.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "macro.c"
# 15 "macro.c"
struct mystruct_withArrays {
int foo;
int bar[MaxN]; int baz[MaxM];
}
struct mystruct_withPointers {
int foo;
int *bar; int *baz;
}
struct otherstruct_withArrays {
int foo;
char bla1[MaxK]; char bla2[MaxL];
}
struct otherstruct_withPointers {
int foo;
char *bla1; char *bla2;
}
mystruct_withArrays hugeA;
mystruct_withPointers smallA;
otherstruct_withArrays hugeB;
otherstruct_withPointers smallB;
smallA.bar = hugeA.bar; smallA.baz = hugeA.baz;
smallB.bla1 = hugeB.bla1; smallB.bla2 = hugeB.bla2;
评论
0赞
arivero
1/13/2022
这种 X Macro 技术看起来确实不错。
2赞
Lundin
1/14/2022
#2
明智的 KISS 解决方案似乎是这样的:
struct mystruct {
int foo;
int *bar;
int *baz;
};
struct mystruct array =
{
.bar = (int[ 1000]){0},
.baz = (int[10000]){0},
};
struct mystruct pointers;
现在,无论数据如何分配,这个结构的接口都是相同的,并且“数组结构”与“指针结构”100%兼容。如果在文件范围内声明,则复合文本的分配将以 ,与伪代码中的处理相同。.bss
评论
0赞
arivero
1/14/2022
我想我仍然可以与 X Macro 结合使用,以避免重复 bar baz ......
0赞
arivero
1/14/2022
这种方法的另一个优点是它不定义“巨大”类型,因此不会错误地将其作为函数参数传递。
0赞
0___________
1/14/2022
或.bar = malloc(100 * sizeof(*array.bar)), .baz = malloc(100000 * sizeof(*array.baz)),
0赞
Lundin
1/14/2022
@0___________在这种情况下,需要在本地范围内声明结构。
0赞
0___________
1/14/2022
@Lundin与问题中相同。指针结构在函数作用域中定义。
评论
myStruct(MaxM,MaxN)
myStruct(,)
myStructArrays(MaxM, MaxN)
MyStructPointers
;
mapStruct(hugeA,smallA)
smallA.bar=hugeA.bar;