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

manage similar structs, one with arrays, the other with pointers

提问人:arivero 提问时间:1/13/2022 最后编辑:arivero 更新时间:1/14/2022 访问量:94

问:

我有一些包含数组的结构

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

C X 宏

评论

5赞 Eric Postpischil 1/13/2022
关于“同样的把戏”:编程不应该通过“把戏”来完成。由于选择是在宏调用 ( versus ) 中指示的,因此将其更改为非棘手:versus 并仅定义两个宏。myStruct(MaxM,MaxN)myStruct(,)myStructArrays(MaxM, MaxN)MyStructPointers
0赞 Bodo 1/13/2022
如果 Eric Postpischil 的简单解决方案不适用于您的实际用例,请展示您稍后要声明的多个结构的示例。也许您可以通过将宏名称作为参数传递给其他宏或使用 X 宏来实现这一点
0赞 arivero 1/13/2022
埃里克,我看不出两个宏如何避免条目 foo bar baz 的双重定义
1赞 chux - Reinstate Monica 1/13/2022
无需摆脱之后.;mapStruct(hugeA,smallA)
1赞 Bodo 1/14/2022
@arivero 我修改了答案中的宏以实现分配等。smallA.bar=hugeA.bar;

答:

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与问题中相同。指针结构在函数作用域中定义。