管理相似的结构,一个用数组,另一个用指针

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 中结束,与伪代码中的处理相同。