ラベルを使用したC構造体の初期化。動作しますが、どのように?
-
05-07-2019 - |
質問
昨日、ループを引き起こした構造体初期化コードを見つけました。次に例を示します。
typedef struct { int first; int second; } TEST_STRUCT;
void testFunc() {
TEST_STRUCT test = {
second: 2,
first: 1
};
printf("test.first=%d test.second=%d\n", test.first, test.second);
}
驚くべきことに(私にとって)、出力は次のとおりです。
-> testFunc
test.first=1 test.second=2
ご覧のとおり、構造体は適切に初期化されます。ラベル付きステートメントがそのように使用できることを知りませんでした。構造体の初期化を行う他の方法をいくつか見てきましたが、オンラインC FAQのいずれにもこの種の構造体の初期化の例は見つかりませんでした。誰がどのように/なぜこれが機能するのか知っていますか?
解決
これは、構造体と配列の両方に指定された初期化子の構文を説明するgccマニュアルのセクションです。
構造初期化子で、初期化するフィールドの名前を指定します 要素値の前に「 .fieldname = 」を付けます。たとえば、 次の構造、
struct point { int x, y; };
次の初期化
struct point p = { .y = yvalue, .x = xvalue };
は同等です
struct point p = { xvalue, yvalue };
GCC 2.5で廃止された同じ意味を持つ別の構文は、次のように「 fieldname:」です。
struct point p = { y: yvalue, x: xvalue };
関連ページはにあります。ここ。
コンパイラには同様のドキュメントが必要です。
他のヒント
これらはラベルでもビットフィールドでもありません。
これは、C99より前の日付までの構造体メンバーを初期化する構文です。標準化されていませんが、たとえばgcc。
typedef struct { int y; int x; } POINT;
POINT p = { x: 1, y: 17 };
C99では、特定の構造体メンバーを初期化するための構文が標準で初めて導入されましたが、外観が少し異なります。
typedef struct { int y; int x; } POINT;
POINT p = { .x = 1, .y = 17 };
はい、上で指摘したように、これらは指定された初期化子であり、標準Cです。ただし、コロンではなくピリオドを使用するように切り替える必要があります。また、ご存知のように、世の中に出回っている本のほとんどは、まだ1984年頃の構文に残っており、言及していません。もっと面白い事実:
-指定された初期化子を使用する場合、指定されていないものはすべてゼロで初期化されます。これは、非常に大きな構造体に役立ちます。例:
typedef struct {
double a, b, c, d, e;
char label[100];
} too_many_type;
too_many_type tm = {.a = 1, .e = 2, .b=1.5};
assert(tm.a + tm.b + tm.c + tm.d + tm.e == 4.5);
assert(!strlen(label));
-また、複合リテラル形式を使用して、非初期化行でこの形式を使用できます。例:
too_many_type tm2;
tm2 = (too_many_type) {.a = 3, .e=6};
これらは本当に素晴らしい機能であり、私が考えることができるすべてのCコンパイラによってサポートされています。それが標準だからです。彼らがあまり知られていないのは残念だ。
実際には「ラベル付きステートメント」ではなく、構造体の名前付きフィールドに初期値を与える方法です。
Gccは、「:」で指定されたイニシャライザを使用しないという警告を出します。C99では、代わりに次のように記述する必要があります。
TEST_STRUCT test = {
.second = 2,
.first = 1
};
この構文はC標準では定義されていません。セクション 6.7.8初期化
の記載
designation:
designator-list =
designator-list:
designator
designator-list designator
designator:
[ constant-expression ]
. identifier
コンパイラが診断メッセージなしでコロン付きの指定を受け入れる場合、コンパイラは標準に準拠していない(または準拠していないように構成されている)ことを意味します。