struct ok中的unsized数组声明?

时间:2014-07-08 19:21:05

标签: c arrays embedded flexible-array-member

以下内容应该对table_type的声明有效,特别是e[]

struct table_type
{
   unsigned int8 a;
   unsigned int8 b;
   unsigned int8 c;
   unsigned int8 d;
   unsigned int8 e[];
};

struct table_type table[] =
{
{  0,   1,  2,  3, {  4,  5,  6,  7,  8} },
{  9,  10, 11, 12, { 13, 14, 15, 16, 17} },
{ 18,  19, 20, 21, { 22, 23, 24, 25, 26} },
{ 27,  28, 29, 30, { 31, 32, 33, 34, 35} },
{ 36,  37, 38, 39, { 40, 41, 42, 43, 44} },
{ 45,  46, 47, 48, { 49, 50, 51, 52, 53} }
};

void main()
{
   unsigned int8 i = 0;
   unsigned int8 j = 0;

   for( i=0; i<6; i++ )
   {
      printf("\n");
      for( j=0; j<=4; j++ )
         printf( "i=%u j=%u k=%u\n", i, j, table[i].e[j] );
   }
}

所有这一切都打印出表格中每行的e元素。这是输出,显然很傻:

  

i = 0 j = 0 k = 4
     i = 0 j = 1 k = 9
     i = 0 j = 2 k = 10
     i = 0 j = 3 k = 11
     i = 0 j = 4 k = 12

     

i = 1 j = 0 k = 13
     i = 1 j = 1 k = 18
     i = 1 j = 2 k = 19
     i = 1 j = 3 k = 20
     i = 1 j = 4 k = 21

     

i = 2 j = 0 k = 22
     i = 2 j = 1 k = 27
     i = 2 j = 2 k = 28
     i = 2 j = 3 k = 29
     i = 2 j = 4 k = 30

     

i = 3 j = 0 k = 31
     i = 3 j = 1 k = 36
     i = 3 j = 2 k = 37
     i = 3 j = 3 k = 38
     i = 3 j = 4 k = 39

     

i = 4 j = 0 k = 40
     i = 4 j = 1 k = 45
     i = 4 j = 2 k = 46
     i = 4 j = 3 k = 47
     i = 4 j = 4 k = 48

     

i = 5 j = 0 k = 49
     i = 5 j = 1 k = 50
     i = 5 j = 2 k = 51
     i = 5 j = 3 k = 52
     i = 5 j = 4 k = 53

请注意,在i=5时,它在最后一个块中是正确的。当我用e[]替换e[5]时,输出都是正确的。我正在使用CCS C编译器和Microchip微控制器。如果这是一个错误或什么,我只是好奇。

2 个答案:

答案 0 :(得分:6)

您正在使用未定义的行为,并且可能同时遇到编译器错误。请注意,GCC 4.9.0(在Ubuntu 12.04衍生版上编译但在Ubuntu 14.04衍生版上运行)为您的代码的这种简单修改提供了许多错误:

#include <stdio.h>
#include <stdint.h>

struct table_type
{
   uint8_t a;
   uint8_t b;
   uint8_t c;
   uint8_t d;
   uint8_t e[];
};

struct table_type table[] =
{
  {  0,   1,  2,  3, {  4,  5,  6,  7,  8} },
  {  9,  10, 11, 12, { 13, 14, 15, 16, 17} },
  { 18,  19, 20, 21, { 22, 23, 24, 25, 26} },
  { 27,  28, 29, 30, { 31, 32, 33, 34, 35} },
  { 36,  37, 38, 39, { 40, 41, 42, 43, 44} },
  { 45,  46, 47, 48, { 49, 50, 51, 52, 53} }
};

int main(void)
{
   uint8_t i = 0;
   uint8_t j = 0;

   for( i=0; i<6; i++ )
   {
      printf("\n");
      for( j=0; j<5; j++ )
         printf( "i=%u j=%u k=%u\n", i, j, table[i].e[j] );
   }
}

编译错误:

$ gcc -g -O3 -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Wold-style-declaration -Werror  -c vla.c
vla.c:15:3: error: initialization of flexible array member in a nested context
   {  0,   1,  2,  3, {  4,  5,  6,  7,  8} },
   ^
vla.c:15:3: error: (near initialization for ‘table[0].e’)
vla.c:16:3: error: initialization of flexible array member in a nested context
   {  9,  10, 11, 12, { 13, 14, 15, 16, 17} },
   ^
vla.c:16:3: error: (near initialization for ‘table[1].e’)
vla.c:17:3: error: initialization of flexible array member in a nested context
   { 18,  19, 20, 21, { 22, 23, 24, 25, 26} },
   ^
vla.c:17:3: error: (near initialization for ‘table[2].e’)
vla.c:18:3: error: initialization of flexible array member in a nested context
   { 27,  28, 29, 30, { 31, 32, 33, 34, 35} },
   ^
vla.c:18:3: error: (near initialization for ‘table[3].e’)
vla.c:19:3: error: initialization of flexible array member in a nested context
   { 36,  37, 38, 39, { 40, 41, 42, 43, 44} },
   ^
vla.c:19:3: error: (near initialization for ‘table[4].e’)
vla.c:20:3: error: initialization of flexible array member in a nested context
   { 45,  46, 47, 48, { 49, 50, 51, 52, 53} }
   ^
vla.c:20:3: error: (near initialization for ‘table[5].e’)

您没有收到类似错误这一事实表明您的编译器相当陈旧,或者没有其他方面的帮助。请注意,即使我启用了严格的编译器警告选项流,编译也会失败,只有gcc -c vla.c的相同消息(仍然是无条件错误)。

您不能拥有具有灵活数组成员的结构数组;不应该允许初始化。您可以拥有指向包含FAM但不包含FAM数组的结构的指针数组。

使用GCC扩展

请注意,这会在没有警告的情况下编译(直到您将-pedantic添加到我使用的编译器选项中):

struct table_type t0 =
  {  0,   1,  2,  3, {  4,  5,  6,  7,  8} };

这导致此代码在我正在使用的系统上运行(但它是使用GCC扩展到标准C的解决方案,正如Shafik Yaghmourcomment所指出的那样):

#include <stdio.h>
#include <stdint.h>

struct table_type
{
   uint8_t a;
   uint8_t b;
   uint8_t c;
   uint8_t d;
   uint8_t e[];
};

struct table_type t0 =
  {  0,   1,  2,  3, {  4,  5,  6,  7,  8} };
struct table_type t1 =
  {  9,  10, 11, 12, { 13, 14, 15, 16, 17} };
struct table_type t2 =
  { 18,  19, 20, 21, { 22, 23, 24, 25, 26} };
struct table_type t3 =
  { 27,  28, 29, 30, { 31, 32, 33, 34, 35} };
struct table_type t4 =
  { 36,  37, 38, 39, { 40, 41, 42, 43, 44} };
struct table_type t5 =
  { 45,  46, 47, 48, { 49, 50, 51, 52, 53} };

struct table_type *pointers[] = { &t0, &t1, &t2, &t3, &t4, &t5 };

int main(void)
{
   uint8_t i = 0;
   uint8_t j = 0;

   for( i=0; i<6; i++ )
   {
      printf("\n");
      for( j=0; j<5; j++ )
         printf( "i=%u j=%u k=%u\n", i, j, pointers[i]->e[j] );
   }
}

示例输出:

i=0 j=0 k=4
i=0 j=1 k=5
i=0 j=2 k=6
i=0 j=3 k=7
i=0 j=4 k=8

i=1 j=0 k=13
i=1 j=1 k=14
i=1 j=2 k=15
i=1 j=3 k=16
i=1 j=4 k=17

i=2 j=0 k=22
i=2 j=1 k=23
i=2 j=2 k=24
i=2 j=3 k=25
i=2 j=4 k=26

i=3 j=0 k=31
i=3 j=1 k=32
i=3 j=2 k=33
i=3 j=3 k=34
i=3 j=4 k=35

i=4 j=0 k=40
i=4 j=1 k=41
i=4 j=2 k=42
i=4 j=3 k=43
i=4 j=4 k=44

i=5 j=0 k=49
i=5 j=1 k=50
i=5 j=2 k=51
i=5 j=3 k=52
i=5 j=4 k=53

(顺便提一下,void main()是非正统的C,除了Microsoft-land;但是,你暗示你在嵌入式系统中工作,也许有特殊的规则。我用标准替换void main() { ... } int main(void) { ... }表示unsigned int8的使用也是非标准的,因为int8不是标准的,但可能来自于嵌入式系统。我将unsigned int8替换为{{1}来自uint8_t

避免GCC扩展

在此示例中,所有数组的大小都相同,因此使用灵活的数组成员表示法确实没有任何优点。因此,避免GCC扩展问题的最简单的解决方案是为阵列提供正确的大小:

<stdint.h>

假设灵活数组成员确实需要不同的大小,那么你必须使用动态内存分配和指向包含FAM的结构的指针数组。

#include <stdio.h>
#include <stdint.h>

struct table_type
{
    uint8_t a;
    uint8_t b;
    uint8_t c;
    uint8_t d;
    uint8_t e[5];
};

struct table_type table[] =
{
    {  0,   1,  2,  3, {  4,  5,  6,  7,  8} },
    {  9,  10, 11, 12, { 13, 14, 15, 16, 17} },
    { 18,  19, 20, 21, { 22, 23, 24, 25, 26} },
    { 27,  28, 29, 30, { 31, 32, 33, 34, 35} },
    { 36,  37, 38, 39, { 40, 41, 42, 43, 44} },
    { 45,  46, 47, 48, { 49, 50, 51, 52, 53} },
};

int main(void)
{
    uint8_t i = 0;
    uint8_t j = 0;

    for (i = 0; i < 6; i++)
    {
        printf("\n");
        for (j = 0; j < 5; j++)
            printf("i=%u j=%u k=%u\n", i, j, table[i].e[j]);
    }
}

示例输出:

#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

struct table_type
{
    uint8_t a;
    uint8_t b;
    uint8_t c;
    uint8_t d;
    uint8_t len;
    uint8_t e[];
};

struct table_type *pointers[6];

struct table_info
{
    uint8_t a;
    uint8_t b;
    uint8_t c;
    uint8_t d;
    uint8_t num;
    uint8_t rep;
    uint8_t info[6];
};

struct table_info data[] =
{
    {  0,   1,  2,  3,  5, 1, {  4,  5,  6,  7,  8,  0, } },
    {  9,  10, 11, 12,  4, 2, { 13, 14, 15, 16,  0,  0, } },
    { 18,  19, 20, 21,  3, 3, { 22, 23, 24,  0,  0,  0, } },
    { 27,  28, 29, 30,  4, 3, { 31, 32, 33, 34,  0,  0, } },
    { 36,  37, 38, 39,  5, 2, { 40, 41, 42, 43, 44,  0, } },
    { 45,  46, 47, 48,  6, 2, { 49, 50, 51, 52, 53, 79, } },
};

int main(void)
{
    for (uint8_t i = 0; i < 6; i++)
    {
        assert(data[i].num * data[i].rep < UINT8_MAX);
        size_t nelem = data[i].num * data[i].rep;
        size_t bytes = sizeof(struct table_type) + nelem * sizeof(pointers[i]->e[0]);
        pointers[i] = malloc(bytes);
        pointers[i]->a = data[i].a;
        pointers[i]->b = data[i].b;
        pointers[i]->c = data[i].c;
        pointers[i]->d = data[i].d;
        pointers[i]->len = data[i].num * data[i].rep;

        uint8_t n = 0;
        for (uint8_t j = 0; j < data[i].rep; j++)
        {
            for (uint8_t k = 0; k < data[i].num; k++)
                pointers[i]->e[n++] = data[i].info[k];
        }
    }

    for (uint8_t i = 0; i < 6; i++)
    {
        printf("index = %2d, a = %2d, b = %2d, c = %2d, d = %2d, len = %2d\n",
               i, pointers[i]->a, pointers[i]->b, pointers[i]->c,
               pointers[i]->d, pointers[i]->len);
        const char *pad = "        ";
        for (uint8_t j = 0; j < pointers[i]->len; j++)
        {
            printf("%s%2d", pad, pointers[i]->e[j]);
            pad = ", ";
        }
        putchar('\n');
    }
}

这仅仅是展示不同大小的灵活阵列成员阵列以及初始化它们的一种方式。更典型的是,您将从某些外部设备收集大小和初始化数据 - 磁盘上的文件或某种类型的I / O通道。

答案 1 :(得分:0)

这是一个C99 灵活的阵列成员

灵活的阵列成员......

  • 写为contents[],没有维度值
  • 类型不完整,因此可能无法应用sizeof运算符
  • 可能只显示为非空的结构的最后一个成员。
  • 包含柔性数组成员的结构或包含此类结构的联合(可能是递归),可能不是结构的成员或数组的元素。

它允许定义结构以用作可变长度对象的标题。