struct ok中的unsized数组声明?

Bas*_*oke 4 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] );
   }
}
Run Code Online (Sandbox Code Playgroud)

所有这一切都打印出表格中每行的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微控制器.如果这是一个错误或什么,我只是好奇.

Jon*_*ler 7

您正在使用未定义的行为,并且可能同时遇到编译器错误.请注意,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] );
   }
}
Run Code Online (Sandbox Code Playgroud)

编译错误:

$ 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’)
Run Code Online (Sandbox Code Playgroud)

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

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

使用GCC扩展

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

struct table_type t0 =
  {  0,   1,  2,  3, {  4,  5,  6,  7,  8} };
Run Code Online (Sandbox Code Playgroud)

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

#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] );
   }
}
Run Code Online (Sandbox Code Playgroud)

样本输出:

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
Run Code Online (Sandbox Code Playgroud)

(顺便提一下,void main()除了Microsoft-land之外,它是非正统的C;但是,你暗示你在嵌入式系统中工作并且可能有特殊规则.我void main() { ... }用标准int main(void) { ... }符号替换.使用unsigned int8也是非标准的,因为int8不是标准,但可能来自是嵌入式系统.我取代unsigned int8uint8_t来自<stdint.h>)

避免GCC扩展

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

#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]);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

#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');
    }
}
Run Code Online (Sandbox Code Playgroud)

示例输出:

index =  0, a =  0, b =  1, c =  2, d =  3, len =  5
         4,  5,  6,  7,  8
index =  1, a =  9, b = 10, c = 11, d = 12, len =  8
        13, 14, 15, 16, 13, 14, 15, 16
index =  2, a = 18, b = 19, c = 20, d = 21, len =  9
        22, 23, 24, 22, 23, 24, 22, 23, 24
index =  3, a = 27, b = 28, c = 29, d = 30, len = 12
        31, 32, 33, 34, 31, 32, 33, 34, 31, 32, 33, 34
index =  4, a = 36, b = 37, c = 38, d = 39, len = 10
        40, 41, 42, 43, 44, 40, 41, 42, 43, 44
index =  5, a = 45, b = 46, c = 47, d = 48, len = 12
        49, 50, 51, 52, 53, 79, 49, 50, 51, 52, 53, 79
Run Code Online (Sandbox Code Playgroud)

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


Cli*_*ord 0

它是C99灵活阵列成员

灵活的数组成员...

  • 被写成contents[]没有尺寸值,
  • 类型不完整,因此可能无法应用 sizeof 运算符,
  • 只能作为非空结构的最后一个成员出现。
  • 包含灵活数组成员的结构或包含此类结构(可能递归)的联合可能不是结构的成员或数组的元素。

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