Cプログラミング言語標準に従って構造体を初期化する方法


466

宣言と初期化で分割されたstruct要素を初期化したい。これは私が持っているものです:

typedef struct MY_TYPE {
  bool flag;
  short int value;
  double stuff;
} MY_TYPE;

void function(void) {
  MY_TYPE a;
  ...
  a = { true, 15, 0.123 }
}

これはMY_TYPE、Cプログラミング言語標準(C89、C90、C99、C11など)に従ってローカル変数を宣言および初期化する方法ですか?それとも、もっと良い、または少なくとも機能しているものはありますか?

更新静的な初期化要素が必要になり、必要に応じてすべてのサブ要素を設定しました。


3
..あなたは本当に私はあなたがガイドをコーディングいくつかの悪いを使用していた見、より良い答えを受け入れる必要がありますが、あなたはまだそれはそれを行うための正しい方法であることを他の人に勧めてはならない
カロリー・ホーバス

@KarolyHorvathよく、良い答えのほとんどはC99に固有です。多分私の質問はstackoverflow.com/questions/6624975/…の複製ですか?
うんざり

もしそれがあなたの当初の意図であったなら、おそらくはい、しかし1)投票は非常に誤解を招くでしょう。2)上位の検索ヒットから、これはC99の方法を示す唯一のヒットです....このページをC99のデモに再利用することをお勧めします...(どうやら人々はこのページをリンクして、それを行う)
Karoly Horvath 2012

10
受け入れられた(そして大きく賛成された)回答が、最初に投稿された場​​合でも、実際には質問に回答しないのは興味深いことです。指定イニシャライザは、宣言を初期化から分割するというOPの問題に対処していません。1999年以前のCの場合、実際の唯一の解決策は、各メンバーに割り当てることです。C99以降では、CesarBの回答にあるような複合リテラルが解決策です。(もちろん、実際のイニシャライザは、デジグネータの有無にかかわらず、さらに優れていますが、どうやらOPには非常に悪いコーディング標準が採用されていました。)
キーストンプソン

32
厳密に言えば、「ANSI C」という用語は現在、ANSIが採用した2011 ISO規格を指します。しかし実際には、「ANSI C」という用語は一般に(公式には廃止された)1989年の標準を指します。たとえば、「gcc -ansi」は、1989年の標準を引き続き適用します。1990年、1999年、および2011年の標準を発行したのはISOなので、「ANSI C」という用語は避け、混乱の可能性がある場合は標準の日付を参照することをお勧めします。
キース・トンプソン

回答:


728

(ANSI)C99では、指定された初期化子を使用して構造体を初期できます。

MY_TYPE a = { .flag = true, .value = 123, .stuff = 0.456 };

編集:他のメンバーはゼロとして初期化されます:「省略されたフィールドメンバーは、静的ストレージ期間を持つオブジェクトと同じように暗黙的に初期化されます。」(https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html


87
素晴らしいです、ありがとう。emをネストすることもできます。static oxeRay2f ray = {.unitDir = {.x = 1.0f、.y = 0.0f}};
orion elenzil 2011年

4
これはまったく質問に答えません。OPは、初期化と宣言を分離したいと考えています。
osvein

3
C99!= ANSI C-したがって、これはC89でもC90でも機能しません。
TimWißmann、2018年

3
C99 ANSI Cです。これを
Cutberto Ocampo

3
@CutbertoOcampo私は今何が起こったのか理解しています。元の質問はANSI Cでの解決策を求めることでしたが、明らかに彼はC89のみの回答を求めていました。2016年に質問が編集され、「ANSI C」が削除されたため、この回答とコメントに「(ANSI)C99」と記載されている理由がわかりにくくなっています。
エティエンヌ

198

複合リテラルでそれを行うことができます。そのページによると、それはC99(これもANSI Cとしてカウントされます)で動作します。

MY_TYPE a;

a = (MY_TYPE) { .flag = true, .value = 123, .stuff = 0.456 };
...
a = (MY_TYPE) { .value = 234, .stuff = 1.234, .flag = false };

初期化子の指定はオプションです。あなたも書くことができます:

a = (MY_TYPE) { true,  123, 0.456 };
...
a = (MY_TYPE) { false, 234, 1.234 };

したがって、指定された初期化子は、宣言と定義を同時に行うときに使用しますが、複合リテラルは、すでに宣言されている変数を定義するときに使用しますか?
Geremia

@Geremiaはどちらの場合も最初に構造体を定義する必要がありますが、指定されたイニシャライザを使用すると、構造体が変更された場合でも、コードが読みやすくなり、エラーに対する耐性が高まります。
hoijui

2
これは少しトリッキーです。多くの場合(一部は成功)、指定された初期化子を使用しようとしました。ただし、オブジェクトの作成時にイニシャライザを使用しない場合はキャストが存在する必要があることが明らかになりました(あなたと@philantの例のおかげです)。ただし、イニシャライザがオブジェクトの作成時以外に使用されている場合(例のように)は、指定されたイニシャライザではなく、複合リテラルと呼ばれることもわかった ideone.com/Ze3rnZ
sherrellbc

93

ANSI C 99に関する回答をすでに受け取っているので、ANSI C 89について骨抜きにします。ANSIC 89では、次の方法で構造体を初期化できます。

typedef struct Item {
    int a;
    float b;
    char* name;
} Item;

int main(void) {
    Item item = { 5, 2.2, "George" };
    return 0;
}

覚えておくべき重要なことは、構造体のオブジェクト/変数を1つでも初期化すると、他のすべての変数はデフォルト値に初期化されるということです。

構造体の値を初期化しない場合、すべての変数に「ガベージ値」が含まれます。

幸運を!


3
初期化で変数を使用することは可能ですか?
シアン、

2
@Cyan自動保存期間を持つオブジェクト用です。open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdfの 6.7.9 13)を参照してください。グローバルオブジェクトの場合、ほとんどリテラルに制限されます。他のグローバルオブジェクトは、たとえconstであっても使用することはできません。
PSkocik

C 99との唯一の違いは、指定を指定できないことですか?
Akaisteph7

42

a = (MYTYPE){ true, 15, 0.123 };

C99でうまくいくだろう


1
正直なところ、答えが最も有用だと思いますが、何でもいいです。
user12211554

22

もうすぐだ...

MY_TYPE a = { true,15,0.123 };

「struct initialize c」 クイック検索するとこれが表示されます


1
これは標準Cには当てはまると思いますが、ANSI C(99?)には当てはまりません。また、宣言と初期化を一度に行うことができないコーディングルールに縛られているため、分割してすべてのサブ要素を初期化する必要があります。
うんざり

8
初期化は宣言の時点でのみ行うことができます。それが「初期化」することの意味です。それ以外の場合は、未定義の値を変数/構造体の初期値として許可し、後で値を割り当てます。
Kieveli 2008

8
ええと...あなたは故意に悪いコーディングルールを持っていますか?「Resource Acquisition Is Initialization」(en.wikipedia.org/wiki/RAII)にそれらを書いた人を紹介する必要があるかもしれません
James Curran

私を信じて、私は本当に、本当に、この時点でこのルールの少しを変更することはできません。それをコード化することは恐ろしく感じます。そして、リビジョン番号などの管理情報を含む静的コードヘッダーなど、70年代には他にも多くのルールがあります。すべてのリリースの変更点は、ソースが変更されていない場合でも...
うんざり

19

Cプログラミング言語標準ISO / IEC 9899:1999(一般にC99として知られています)では、指定された初期化子を使用して、次のように構造体または共用体のメンバーを初期化できます。

MY_TYPE a = { .stuff = 0.456, .flag = true, .value = 123 };

ISO / IEC 9899:1999規格のparagraph 7セクション6.7.8 Initializationで次のように定義されています。

デジグネーターがフォームを持つ場合

次に、識別子(現在定義されているオブジェクト)は構造型または共用体型を持ち、識別子はその型のメンバーの名前になります。

paragraph 9同じセクションで次のように述べていることに注意してください。

特に明記されていない限り、この副次的な目的のために、構造および共用体型のオブジェクトの名前のないメンバーは初期化に参加しません。構造オブジェクトの名前のないメンバーは、初期化後も不確定な値を持っています。

ただし、GNU GCC実装では、省略されたメンバーはゼロまたはゼロのような型に適した値として初期化されます。GNU GCCドキュメントのセクション6.27指定イニシャライザで述べたように:

省略されたフィールドメンバーは、静的ストレージ期間を持つオブジェクトと同じように暗黙的に初期化されます。

Microsoft Visual C ++コンパイラは、公式ブログの投稿C ++ Conformance Roadmapによると、バージョン2013以降、指定された初期化子をサポートする必要があります。MSDN Visual StudioドキュメントInitializing unions and structsInitializersの記事の段落は、名前のないメンバーがGNU GCCと同様にゼロのような適切な値に初期化されることを示唆しています。

ISO / IEC 9899: 1999に取って代わったISO / IEC 9899:2011標準(一般にC11として知られています)は、セクションの下で指定された初期化子を保持します6.7.9 Initialization。また、paragraph 9変更されずに保持されます。

ISO / IEC 9899:2011に取って代わった新しいISO / IEC 9899:2018標準(一般にC18として知られています)は、セクションの下で指定された初期化子を保持します6.7.9 Initialization。また、paragraph 9変更されずに保持されます。


3
最初は、これを承認された回答の編集として提案しましたが、拒否されました。したがって、私はそれを回答として投稿します。
PF4Public 2016年

「名前のないメンバー」は「省略されたフィールド」を意味するのではなく、のユニオンのような「匿名のメンバー」を意味すると思いますstruct thing { union { char ch; int i; }; };。標準は後で述べています:「ブレースで囲まれたリストの初期化子が集合体の要素またはメンバーよりも少ない場合、または既知のサイズの配列の初期化に使用される文字列リテラルの文字が配列の要素よりも少ない場合、集約の残りの部分は、静的ストレージ期間を持つオブジェクトと同じように暗黙的に初期化されます。」
出現

14

ロン・ヌニが言ったように:

typedef struct Item {
    int a;
    float b;
    char* name;
} Item;

int main(void) {
    Item item = {5, 2.2, "George"};
    return 0;
}

覚えておくべき重要なこと:構造体の1つのオブジェクト/変数でも初期化すると、他のすべての変数はデフォルト値に初期化されます。

構造体の値を初期化しない場合(つまり、その変数を宣言するだけの場合)、宣言がローカルである場合variable.membersのみ、すべてに「ガベージ値」が含まれます

宣言がグローバルまたは静的である場合(この場合のように)、初期化されていないものvariable.membersはすべて、次のように自動的に初期化されます。

  • 0 整数と浮動小数点
  • '\0'ためchar(もちろんこれはちょうど同じであるの0、そしてchar整数タイプです)
  • NULL ポインタ用。

ローカル/グローバルについて興味深いことに、これはstruct tm時間値にも適用されます。私はローカルのものを持っていて、ある場合にはDSTがオンでしたが、別の場合にはそうではありませんでした。私はDST(tm_isdstフィールド)を使用していませんでしたが、これはstrptimeからのものでしたが、time_tに変換すると、1時間ずれていました。
Alan Corey

3
void function(void) {
  MY_TYPE a;
  a.flag = true;
  a.value = 15;
  a.stuff = 0.123;
}

24
「初期化は割り当てとは異なる」と聞いたことがあります。これは初期化ではなく割り当てではありませんか?
HayriUğurKoltuk

2

MSがC99に更新されていない場合、MY_TYPE a = {true、15,0.123};


2

構造体を初期化する別の方法を見つけました。

構造体:

typedef struct test {
    int num;
    char* str;
} test;

初期化:

test tt = {
    num: 42,
    str: "nice"
};

GCCのドキュメントによると、この構文はGCC 2.5以降廃止されています。


2

私はこれらの答えのどれも好きではなかったので自分で作りました。これがANSI Cかどうかはわかりませんが、デフォルトモードのGCC 4.2.1にすぎません。ブラケットを思い出せないので、データのサブセットから始めて、シャットダウンするまでコンパイラエラーメッセージと戦います。読みやすさが私の最優先事項です。

    // in a header:
    typedef unsigned char uchar;

    struct fields {
      uchar num;
      uchar lbl[35];
    };

    // in an actual c file (I have 2 in this case)
    struct fields labels[] = {
      {0,"Package"},
      {1,"Version"},
      {2,"Apport"},
      {3,"Architecture"},
      {4,"Bugs"},
      {5,"Description-md5"},
      {6,"Essential"},
      {7,"Filename"},
      {8,"Ghc-Package"},
      {9,"Gstreamer-Version"},
      {10,"Homepage"},
      {11,"Installed-Size"},
      {12,"MD5sum"},
      {13,"Maintainer"},
      {14,"Modaliases"},
      {15,"Multi-Arch"},
      {16,"Npp-Description"},
      {17,"Npp-File"},
      {18,"Npp-Name"},
      {19,"Origin"}
    };

データは、タブ区切りファイルとして開始され、検索して別のものにマッサージすることができます。はい、これはDebianのものです。したがって、{}(配列を示す)の外側のペアの1つと、内部の各構造体の別のペアです。間にコンマを入れます。ヘッダーに物を置くことは必ずしも必要ではありませんが、構造体には約50の項目があるので、コードを混乱させないようにするためと、簡単に置き換えることができるように、それらを別のファイルに入れます。


3
構造体の配列の初期化について質問はありませんでした!つまり、あなたの答えにはオーバーヘッドが含まれています。
ビクターSignaevskyi

私のポイントは、すでに値が含まれている構造体を宣言することと、=を使用して後で各値を設定することでした。
アランコーリー

その原則は、それが1つの構造体であっても、それらの配列であっても適用されます。=の使用は実際には初期化ではないので、私は思いません。
アランコーリー

0

Cの構造体は、次のように宣言および初期化できます。

typedef struct book
{
    char title[10];
    char author[10];
    float price;
} book;

int main() {
    book b1={"DS", "Ajay", 250.0};

    printf("%s \t %s \t %f", b1.title, b1.author, b1.price);

    return 0;
}

0

集約型の初期化に関するMicrosoft Visual Studio 2015のドキュメントをまだ読みましたが、での初期化のすべての形式が{...}そこで説明されていますが、「designator」という名前のドットでの初期化については言及されていません。それも機能しません。

C99標準の第6.7.8章の初期化では、指定子の可能性について説明していますが、私の頭では、複雑な構造体については明確ではありません。pdfとしてC99標準

私の考えでは、

  1. = {0};すべての静的データに-initializationを使用します。マシンコードの労力が減ります。
  2. たとえば、初期化にはマクロを使用します

    typedef MyStruct_t{ int x, int a, int b; } MyStruct; define INIT_MyStruct(A,B) { 0, A, B}

マクロを適応させることができ、その引数リストは、変更された構造体の内容に依存しません。初期化する要素を少なくする必要がある場合は適切です。ネストされた構造体にも適しています。3.簡単な形式は次のとおりです。サブルーチンで初期化します。

void init_MyStruct(MyStruct* thiz, int a, int b) {
  thiz->a = a; thiz->b = b; }

このルーチンは、CではObjectOrientedのように見えます。C++でもコンパイルしthizないthisように、を使用してください。

MyStruct data = {0}; //all is zero!
init_MyStruct(&data, 3, 456);

0

私は自分の構造体を初期化する良い方法を探していました、そして私は以下を使用する必要があります(C99)。これにより、プレーンな型と同じ方法で、単一の構造または構造の配列を初期化できます。

typedef struct {
    char *str;
    size_t len;
    jsmntok_t *tok;
    int tsz;
} jsmn_ts;

#define jsmn_ts_default (jsmn_ts){NULL, 0, NULL, 0}

これは、コードで次のように使用できます。

jsmn_ts mydata = jsmn_ts_default; /* initialization of a single struct */

jsmn_ts myarray[10] = {jsmn_ts_default, jsmn_ts_default}; /* initialization of
                                                    first 2 structs in the array */

しかし、これは構造体の配列をデフォルト値に初期化しません。配列の最初の構造をで指定された値に初期化しますjsmn_ts_defaultが、残りの構造は、配列に静的ストレージ期間があるかのように初期化さNULL0ます。つまり、メンバーはおよびに初期化されます。しかし、変更する#define jsmn_ts_default (jsmn_ts){"default", sizeof "default", NULL, 0}と、最初の配列要素だけが初期化されることがわかります。
ex nihilo 2018

はい、私はより多くのテストから戻ったばかりで、投稿を編集したいと思っていました:)ところで、同じ動作がint a[10] = {1};最初の要素のみで発生します==1
div0man
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.