我的问题与此有关: c define arrays in struct with different sizes
但是,我不想使用动态分配(嵌入式目标)。
在 C 中,我希望有两个相同结构的版本,每个版本的静态数组都有不同的大小。 两个结构都将通过指针参数由相同的函数使用。
typedef struct {
short isLarge; //set 0 at initialization
short array[SIZE_A];
//more arrays
} doc_t;
typedef struct {
short isLarge; //set 1 at initialization
short array[SIZE_B];
//more arrays
} doc_large_t;
void function( doc_t* document ) {
if ( document->isLarge ) {
//change document into doc_large_t* [1]
}
//common code for both doc_t and doc_large_t
}
(1)上面的描述需要一种方法来动态地将指针doc_t *指针转换为doc_large_t * document [1]。那可能吗 ?怎么样?
(2)我遇到的另一个解决方案是为两个结构都有一个公共的头数据部分,不仅包括isLarge标志,还包括指向以下静态数组的指针。这有多难啊?
(3)另外,你有一个很好的技巧或可以使用的工作吗?
编辑:
我的应用程序是在嵌入式MCU上寻找路径。
我有几何对象,比如多边形。多边形可以描述简单的矩形障碍物,以及更复杂的形状(例如可访问区域)。
复杂多边形可能有大量顶点,但数量很少。简单的多边形很常见。
两者都将使用相同的算法。 我事先知道哪个多边形需要更多顶点。
我要做的是优化工作记忆,使其适合MCU。 (即小形状得到小阵列;复杂形状得到大阵列)
答案 0 :(得分:2)
类似于你在问题中提到的想法(指向数组的指针),但只有一个指针:
typedef struct
{
short array[SIZE_B - SIZE_A];
// more arrays alike...
} Extension;
typedef struct
{
short array[SIZE_A];
//more arrays (all the small ones!)
Extension* extraData;
} doc_t;
如果extraData为NULL,则您有一个小的多边形,否则,您会在引用的结构中找到其他数据。承认,迭代大多边形的所有值会有点讨厌......
如果可以为每种对象类型使用预定义大小的全局数组(正如Dominic Gibson所提出的那样 - 顺便说一下这是一个好主意),你可以通过用函数替换它来节省isLarge标志。 :
int isLarge(void* ptr)
{
return
(uintptr_t)globalLargeArray <= (uintptr_t)ptr
&&
(uintptr_t)ptr < (uintptr_t)globalLargeArray + sizeof(globalLargeArray);
}
当然,所有多边形(在上面的情况下:至少是大的多边形)必须存在于此数组中才能使其工作。如果你动态地或者在其他地方创建至少一个(堆栈,另一个全局变量) - 我们就出去了......
答案 1 :(得分:1)
全局创建数组并使用指针指向大数组或小数组。
答案 2 :(得分:0)
您应该尝试保留单个结构,并且对于不同的数组大小,将它们放在union
中。我不知道以下结构是否对您的案例有意义。
typedef struct {
short isLarge; //manually set to 0 or 1 after creating structure
//and accordingly initialize the arrays in below union
union my_varying_arrays {
short array_A[SIZE_A];
short array_B[SIZE_B];
};
//more arrays
} doc_t;
如果isLarge
为0
,请设置array_A
数组的值,如果1
设置数组array_B
的值。
答案 3 :(得分:0)
您可以使用const
对特定数组执行此操作,因为数据为void *
。
然后根据结构中的属性,将void *
转换为您需要的内容。
在运行时需要结构时会变得更复杂。 特别是在嵌入式目标上。
typedef struct {
short size;
void *array;
} doc_t;
其中array
指向内存管理器分配的内存块。
您现在必须决定是使用C标准malloc
还是使用基于最大块大小的池内存系统。
一个例子是ChibiOS Memory pools。
如果您随机分配和释放可变大小的内存块,则可能会造成内存碎片化。
如果你逐步分配,你不必担心内存。只需创建一个大块并跟踪您的位置。有点像堆栈。
答案 4 :(得分:0)
编辑之后,我认为您可以做的最好的事情是分析您的需求,定义目标可以管理的最大简单和复杂多边形,然后声明一个单面和常见多边形池,如:
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#define MAX_COMPLEX 16
#define MAX_SIMPLE 16
uint16_t g_Simple_Poly_set[MAX_COMPLEX][SIZE_A];
uint16_t g_Complex_Poly_set[MAX_COMPLEX][SIZE_B];
uint16_t g_Simple_Poly_used = 0;
uint16_t g_Complex_Poly_used = 0;
struct poly
{
bool isLarge;
uint16_t *vetexes;
};
bool create_poly_simple (struct poly *p)
{
bool retVal = false; // default: not more space for poly
if (g_Simple_Poly_used < MAX_SIMPLE)
{
p->isLarge = false;
p->vetexes = &g_Simple_Poly_set[g_Simple_Poly_used][0];
g_Simple_Poly_used++;
retVal = true;
}
return retVal;
}
bool create_poly_compleX (struct poly *p)
{
bool retVal = false; // default: not more space for poly
if (g_Complex_Poly_used < MAX_COMPLEX)
{
p->isLarge = true;
p->vetexes = &g_Complex_Poly_set[g_Complex_Poly_used][0];
g_Complex_Poly_used++;
retVal = true;
}
return retVal;
}
void your_stuff_with_poly ( struct poly *p)
{
uint32_t poly_size = (p->isLarge == false) ? SIZE_A : SIZE_B;
// your stuff with the correct size
}
这是一个为静态&#34;实例化而设计的简单实现&#34;结构。您还可以使用create / destroy函数来增强代码,该函数可以跟踪哪些数组可以自由使用。
答案 5 :(得分:-1)
你的2号解决方案是正确的想法。我不清楚为什么你认为这很难看。也许这个美丽的实现会改变你的想法。
您可以通过将基础结构作为继承结构的第一个成员来实现单继承。然后可以使用指向基类型的指针来引用继承对象。
typedef struct {
short doc_type;
short *array_ptr;
// more array pointers
} doc_base_t;
typedef struct {
doc_base_t base; // base.doc_type set 0 at initialization
short array[SIZE_A]; // base.array_ptr initialized to point here
//more arrays
} doc_small_t;
typedef struct {
doc_base_t base; // base.doc_type set 1 at initialization
short array[SIZE_B]; // base.array_ptr initialized to point here
//more arrays
} doc_large_t;
void function( doc_base_t* document ) {
if ( document->doc_type == 1) {
// array size is large
} else {
// array size is small
}
//common code referencing arrays through doc_base_t->array_ptr
}
array_ptr
中的doc_base_t
成员对于继承机制不是必需的。但我特意为#34;共同代码添加了#34;你的部分功能。如果doc_base_t
未包含array_ptr
,那么您可以根据{{1}将通用document
转换为doc_small_t
或doc_large_t
类型价值。但是,您可能需要为每个继承的类型使用不同的实现。通过将base_type
成员添加到array_ptr
,我怀疑您可以为所有继承类型编写一个通用实现。
因此,您将静态声明doc_base_t
和doc_small_t
的所有实例。在初始化每个对象时,您将初始化doc_large_t
和base.doc_type
成员。然后,在调用base.array_ptr
之前,您将把两种类型的对象强制转换为doc_base_t。 (或者传递function
成员的地址,这会产生相同的指针值。)
更新示例:
base
答案 6 :(得分:-2)
使用malloc()
或类似的动态分配方法很容易。只需使用灵活的阵列成员:
typedef struct {
short isLarge; //set 0 at initialization
.
.
.
short array[SIZE_A];
short largeArray[];
} doc_t;
分配&#34;小结构&#34;:
doc_t *small = malloc( sizeof( *small ) );
small->isLarge = 0;
分配&#34;大型结构&#34;:
doc_t *large = malloc( sizeof( *large ) + ( SIZE_B - SIZE_A ) * sizeof( large->largeArray[ 0 ] );
large->isLarge = 1;
请注意,您必须保留largeArray
元素最后,这意味着array
元素必须是倒数第二个才能使其生效。
根据您自己分配的方式,这可能适用也可能不适用。
(它也有点像黑客,因为它取决于能够通过在largeArray
上使用SIZE_A
或更高的索引来访问array
中的数据。那个访问其界限之外的对象......)