您正在使用未定义的行为,并且可能同时遇到编译器错误。请注意,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 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] );
}
}
样本输出:
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 是非正统的;但是,您暗示您在嵌入式系统中工作,并且可能有特殊规则。我void main() { ... }
用标准int main(void) { ... }
表示法替换。使用unsigned int8
也是非标准的,因为int8
不是标准,但可能来自嵌入式系统。我用unsigned int8
fromuint8_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]);
}
}
假设灵活的数组成员实际上需要不同的大小,那么您必须使用动态内存分配和指向包含 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');
}
}
示例输出:
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
这只是演示不同大小的灵活数组成员数组并对其进行初始化的一种方式。更典型的是,您会从某个外部设备(磁盘上的文件或某种 I/O 通道)收集大小和初始化数据。