如何在C中包含一个可变大小的数组作为结构成员?

时间:2015-04-07 14:03:44

标签: c arrays static malloc misra

我必须说,在一个看似基本的问题上我有一个难题。我有一个结构,我想将一个数组存储为一个字段。我想在不同的上下文中重用这个结构,有时候我需要一个更大的数组,有时候需要更小的数组。 C禁止使用可变大小的缓冲区。因此,自然的方法是将指向此数组的指针声明为struct member:

struct my {
    struct other* array;
}

然而,这种方法的问题是我必须遵守MISRA-C的规则,该规则禁止动态内存分配。那么如果我想分配内存并初始化数组,我就不得不这样做:

var.array = malloc(n * sizeof(...));

这是MISRA标准禁止的。我怎么能这样做?

3 个答案:

答案 0 :(得分:2)

由于您正在关注MISRA-C,我猜测该软件在某种程度上是关键任务,在这种情况下,所有内存分配必须是确定性的。每个安全标准都禁止堆分配,不仅仅是MISRA-C,还有更一般的安全标准(IEC 61508,ISO 26262,DO-178等)。

在这样的系统中,您必须始终设计最坏情况,这将消耗最多的内存。你需要准确分配那么多空间,不多也不少。在这样的系统中,其他一切都没有意义。

鉴于这些先决条件,您必须分配大小为LARGE_ENOUGH_FOR_WORST_CASE的静态缓冲区。一旦你意识到这一点,你只需要找到一种方法来跟踪你在这个缓冲区中存储的数据类型,方法是使用枚举和可能的“使用大小”计数器。


请注意,MISRA-C:2012不仅禁止malloc / calloc,还禁止使用VLA和灵活阵列成员。如果您使用的是C90 / MISRA-C:2004,则没有VLA,也没有任何明确定义的灵活数组成员使用 - 它们在C99之前调用了未定义的行为。

答案 1 :(得分:0)

编辑:此解决方案不符合MISRA-C规则。

你可以种类在结构定义中包含VLA,但仅限于它在函数内部。解决这个问题的一种方法是在主结构的末尾使用“灵活的数组成员”,如下所示:

#include <stdio.h>
struct my {
  int len;
  int array[];
};

您可以创建对此结构进行操作的函数。

void print_my(struct my *my) {
  int i;
  for (i = 0; i < my->len; i++) {
    printf("%d\n", my->array[i]);
  }
}

然后,要创建此结构的可变长度版本,您可以在函数体中创建一种新类型的结构,包含my结构,还可以定义该缓冲区的长度。这可以通过变化的尺寸参数来完成。然后,对于您调用的所有函数,您只需传递指向包含的struct my值的指针,它们就能正常工作。

void create_and_use_my(int nelements) {
  int i;

  // Declare the containing struct with variable number of elements.
  struct {
    struct my my;
    int array[nelements];
  } my_wrapper;

  // Initialize the values in the struct.
  my_wrapper.my.len = nelements;
  for (i = 0; i < nelements; i++) {
    my_wrapper.my.array[i] = i;
  }

  // Print the struct using the generic function above.
  print_my(&my_wrapper.my);
}

您可以使用nelements的任何值调用此函数,它将正常工作。这需要C99,因为它确实使用了VLA。此外,还有一些GCC extensions使这更容易。

重要提示:如果您将struct my传递给另一个函数,而不是指向它的指针,我几乎可以保证它会导致各种错误,因为它赢了“用它复制可变长度数组。

答案 2 :(得分:0)

这可能完全不适合您的情况,但考虑到您的限制,我不确定如何处理它。

创建一个大型静态数组,并将其用作&#34; heap&#34;:

static struct other heap[SOME_BIG_NUMBER];

然后你会分配&#34;记忆来自这个&#34;堆&#34;像这样:

var.array = &heap[start_point];

你必须做一些记账,以便跟踪你的&#34;堆&#34;已经分配。这假设您对可执行文件的大小没有任何重大限制。