3

test1次の例では、2 つの構造体とを使用してこれを示していtest2ます。最初の構造体には 2 つの要素 (サイズ 2 の整数配列) と浮動小数点数要素があります。

test1の2 つの構造体変数s1s2を次のように初期化します。

s1={{23,52},2.5},s2={21,19,3.6};

s2の場合でも、配列要素を囲む中括弧を取り出しても、両方とも正常に動作します。警告なしで正常に動作し、出力は正しいです。しかし、次のようにtest2の 2 つの変数を初期化すると、次のようになります。

 v1={{23,52},2.5},v2={21,19,3.6};

v1の値を出力しようとすると、間違った出力が表示されます。これらは、コンパイル時に表示された警告です。

warning: braces around scalar initializer|
warning: (near initialization for 'v1.list1')|
warning: excess elements in scalar initializer|
warning: (near initialization for 'v1.list1')|
||=== Build finished: 0 errors, 4 warnings ===|

この前提に基づいて、以下の疑問を解消してください。

質問:最初の 2 つの数値が構造体の別個の整数要素であるか、構造体の整数配列要素の一部であるかについてコンパイラーを混乱させるv1={{23,52},2.5}代わりにs2には、 2 つの要素 (サイズ 2 の 1 つの整数配列と float) ではなく、 3 つの要素 (2 つの整数要素と 1 つの float) がありますか?私が特に理解したいのは、v1の初期化に関する最初のケースが間違っている理由です。v1={23,52,2.5}s2={21,19,3.6}s2={{21,19},3.6}

#include<stdio.h>

struct test1{
int list[2];
float rate;
}s1={{23,52},2.5},s2={21,19,3.6}; //Works fine

struct test2{
int list1;
int list2;
float rate;
}v1={{23,52},2.5},v2={21,19,3.6};  //Messes things up

int main(void)
{
    printf("%d,%d,%f\n",s1.list[1],s2.list[1],s2.rate);
    printf("%d,%d,%f\n",v1.list1,v1.list2,v1.rate);
}
4

2 に答える 2

4

これは、イニシャライザのルールがどのように定義されているかの結果にすぎません。初期化の現在のオブジェクトstructが、unionまたは配列である場合、次の初期化子が a で始まる場合、{その中かっこで囲まれた初期化子とその一致}がそのオブジェクトのメンバーの初期化に使用されます。それ以外の場合は、イニシャライザのリストをたどって、必要なだけ取得します。

したがって、最初のケースs1={{23,52},2.5}では、現在のオブジェクトは として開始されs1.listます。これは配列であり、次の初期化子は{ 23, 52 }であるため、配列の初期化に使用されます。 s1.rateが現在のオブジェクトになり、次の初期化子が2.5になるため、期待どおりに動作します。

2 番目のケースs2={21,19,3.6}では、現在のオブジェクトは として開始されs2.listます。これは配列ですが、次のイニシャライザは - で始まらないため{、必要な数の値 (この場合は 2 つ) を取り、 と で配列を初期化し21ます19s2.rateが現在のオブジェクトになり、次の初期化子が2.5になるため、これも期待どおりに機能します。

3 番目のケースv1={{23,52},2.5}では、現在のオブジェクトは として開始されv1.list1ます。これはスカラーで、対応する初期化子は{23, 52}です。これは、言語の制約に違反しています- 「スカラーの初期化子は、オプションで中括弧で囲まれた単一の式でなければなりません」-そのため、警告が表示されます。正式にはプログラムの動作は定義されていませんが、コンパイラはイニシャライザに含まれる最初の値のみを使用し、余分な値を破棄しているようです。現在のオブジェクトはv1.list2であり、次の初期化子は2.5であるため、このメンバーの初期化に間違った値が使用されています。の初期化子はありませんv1.ratev1静的な保存期間があるため、このメンバーは への初期化子です0.0

4 番目のケースv2={21,19,3.6}では、現在のオブジェクトは として開始されv1.list1、次のイニシャライザは21- この値はメンバーの初期化に使用されます。この後、現在のオブジェクトはv1.list2であり、次の初期化子は19です。thenv1.rateは現在のオブジェクトで、次の初期化子は3.6です。

混乱を最小限に抑えるために、各structまたは配列サブオブジェクトには常に中括弧で囲まれた初期化子を使用する必要があります。

于 2013-05-13T04:56:43.883 に答える
0

変数の場合s2、コンパイラは埋め込み配列のサイズを認識しているため、ブレーサーがなくても適切に割り当てることができます。ただし、ブレーサーの使用を提案する警告が表示される場合があります。使用しない場合は、コンパイラの警告をさらに有効にすることをお勧めします (警告は、有効な C であるが無効なロジックである可能性があるエラーを示している可能性があるため、修正することをお勧めします)。

の場合v1、複合データ型 (構造体/共用体/配列) がないため、追加のブレイサーを使用できません。ブレーサー{}は、複合データ型の初期化にのみ使用できます。

于 2013-05-13T07:43:23.343 に答える