未定義の動作を使用しており、おそらく同時にコンパイラのバグに遭遇しています。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} };
これは、私が使用しているシステムで動作するこのコードにつながります(ただし、コメントでShafik Yaghmourが指摘したように、標準Cへの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[];
};
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()
は Microsoft ランド以外では非正統的な C ですが、組み込みシステムで作業していることを暗示しており、それには特別な規則がある可能性があります。void main() { ... }
標準のint main(void) { ... }
表記法に置き換えました。の使用unsigned int8
も非標準ですint8
。標準ですが、おそらく組み込みシステムであることから来ています. fromに置き換えunsigned int8
ました)uint8_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
これは、さまざまなサイズの柔軟な配列メンバー配列を示し、それらを初期化する 1 つの方法にすぎません。より一般的には、外部デバイス (ディスク上のファイルまたは何らかの I/O チャネル) からサイズおよび初期化データを収集します。