C相同结构大小不同

时间:2017-04-12 05:44:40

标签: c arrays pointers embedded structure

我的问题与此有关: 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。 (即小形状得到小阵列;复杂形状得到大阵列)

7 个答案:

答案 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;

如果isLarge0,请设置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_tdoc_large_t类型价值。但是,您可能需要为每个继承的类型使用不同的实现。通过将base_type成员添加到array_ptr,我怀疑您可以为所有继承类型编写一个通用实现。

因此,您将静态声明doc_base_tdoc_small_t的所有实例。在初始化每个对象时,您将初始化doc_large_tbase.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中的数据。那个访问其界限之外的对象......)