管理相似的结构,一个用数组,另一个用指针
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
创建多个类似结构的可能解决方案是使用 X macro。
(与维基百科页面不同,我将宏 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;
明智的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
中结束,与伪代码中的处理相同。
我有一些包含数组的结构
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
创建多个类似结构的可能解决方案是使用 X macro。
(与维基百科页面不同,我将宏 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;
明智的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
中结束,与伪代码中的处理相同。