質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.91%

構造体の初期化についてのコンパイラの振る舞い

受付中

回答 4

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 556

seiken

score 4

前提・実現したいこと

構造体を初期化しようと、下記のようなコードを書きました。clangではコンパイルが通るのですが、GCC 8.30では、コンパイルすることができません。そもそもこのような初期化はできないということなのでしょうか。

また、言語仕様としてはどのようになっているのかご存じの方がいらっしゃいましたら、ポインタなど教えていただけるとうれしいです。

発生している問題・エラーメッセージ

コンパイルすると下記のメッセージが表示されます。

test.cpp: In functionint main()’:
test.cpp:16:3: error: C99 designatorhogeoutside aggregate initializer
   };
   ^

該当のソースコード

struct foo {
  char hoge[32];
};

union bar {
  foo f;
  foo g;
};

int main()
{
  bar a = {
     .f = {
         .hoge = "Hello world"
         }
  };
}

上記コードをもう少し単純にしてみました。

struct foo {
  char hoge[32];
};

foo a = {
  .hoge = "Hello world"
};

試したこと

Appleのclang、あるいはDebianにインストールしたclang 7.0.1ではコンパイルすることができました。

どうぞよろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+3

指示付き初期化子とかいう書き方っぽいですが,コンパイラ毎に対応状況が違うということなのではないでしょうか.
(リンク先では「C++20以上」と書かれています.)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/03/03 17:45

    それ具体的にどういうコードですか???

    キャンセル

  • 2020/03/03 17:53

    通るパターンと通らないパターンがあるという話なのであれば…通るパターンのコードもその旨と共に質問文内に書けば,誰か詳しい人が納得な回答してくれるかもしれませんね.

    キャンセル

  • 2020/03/03 17:55 編集

    ↓コンパイル通りますね。。。
    struct foo {
    int hoge[2];
    };

    union bar {
    foo f;
    foo g;
    ;

    int main()
    {
    bar a = {
    .f = {
    .hoge = {1,9}
    }
    };
    }

    キャンセル

+1

fanaさんが張っているリンク先(ノートの部分)にも書いていますが、ネストされた指示付き初期化子はCでは有効でもC++では無効です。

clang++ prog.cc -Wall -Wextra -std=c++2a | Wandboxでコンパイル

と、一見通るように見えますが、

clang++ prog.cc -Wall -Wextra -std=c++2a -pedantic-errors | Wandboxでコンパイル

厳密に仕様通りかチェックを入れるとエラーになります。

言ってしまえ、現在制定段階のC++2aの規格としては間違った書き方ですが、Cの仕様に合わせてClangでは言語仕様を拡張してサポートしているが、GCCはしていないというただそれだけです。C++2aはまだ仕様として確定ではないので、CのようにOKとなる可能性はあります。

なおC11ならGCCでも厳密仕様で通ります。

gcc prog.c -Wall -Wextra -std=c11 -pedantic-errors | Wandboxでコンパイル (C用にちょっと書き換え)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/03/04 01:07

    どうやら、「Designated Initialization(指示付きの初期化)にはまだコンパイラが対応していないよ、でclangはC99仕様だからまっいっか、でコンパイルしてくれる、ということのように思いますが、結論を導きたいのでもう少しお付き合いいただけませんか?

    で、この問題ネストとは違うように思います。
    もう少し分解してみました。

    ``` C++
    struct foo {
    int hiyo;
    char hoge[32];
    };

    foo a {
    .hiyo =1,
    .hoge = "Hello world"
    };
    ```

    これでclangで仕様チェックしたらやはりエラーになります。

    そこで、

    ``` C++
    struct foo {
    int hiyo;
    char hoge[32];
    };

    foo a {
    1,
    "Hello world"
    };
    ```

    とすると、clangでもGCCでもコンパイルできました。

    どうでしょう、これで間違いなさそうなら、まとめを投稿してみます。

    キャンセル

  • 2020/03/04 19:20 編集

    まず、ネストはC++2aでは規格違反であることに注意してください。

    色々試すと`.hoge = {'H', '\0'}`は通りますが`.hoge = "H"`は通りません。かといって、`hoge`を`cost char *`や`std::string`にすると通ります。

    ぶっちゃけ、よくわかりません。Cでは`{'H', '\0'}`と`"H"`は同等ですが、C++では文字配列の文字列リテラルの初期化として文法上の解釈が異なるため、そういった所から仕様上NGなのかも知れません。
    (`const char *a = "abc";`と`const char a[] = "abc";`は動作だけでなく、初期化子の解釈の仕方そのもの(言わば文法)が異なるということ)

    キャンセル

  • 2020/03/05 11:43

    追試ありがとうございました。どうやら踏み込まないほうが良い部分に踏み込んだ気がします。Designated Initialization自体がC++としては新しい機能なのですね。ネストというのは、`.a.b`のような書き方を指していると解釈しています。今回問題にしたのはその部分ではないです。構造体の中のメンバの型がなんであれ、Designated Initializationすると、clangで`-pedantic-errors`指定でコンパイルするとエラーにしますね。

    キャンセル

0

気になったのでちょっと調査しました。

集成体初期化#Character_arrays

文字型 (char、 signed char、 unsigned char、 char8_t、 char16_t、 char32_t、 wchar_t) の配列は、適切な文字列リテラル (波括弧で囲っても構いません) から初期化できます。 文字列リテラルの連続する文字 (暗黙の終端のヌル文字を含みます) が、配列の要素を初期化します。 配列のサイズが指定されていて、それが文字列リテラルの文字数より大きい場合、残りの文字はゼロ初期化されます。

この「配列のサイズが指定されていて、それが文字列リテラルの文字数より大きい場合、残りの文字はゼロ初期化されます」が対応できてない感じです。

以下の結果になったので、初期化時サイズぴったりに初期化するとOKで短いとNGな気がします。(char配列の場合)

g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0しか手元にないのでこれで確認。

これ↓はOK

struct foo {
        char hoge[4];
};

int main()
{
        foo a = {
                .hoge = "abc"
        };
}

これ↓はエラー

struct foo {
        char hoge[5];
};

int main()
{
        foo a = {
                .hoge = "abc"
        };
}

但し、char以外の場合(例えばint配列)は、要素数より短くてもOKな感じ。

struct foo {
        int hoge[2];
};

union bar {
        foo f;
        foo g;
};

int main()
{
        bar a = {
                .f = {
                        .hoge = {1}
                }
        };
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/03/04 00:11

    調査ありがとうございます。

    現実的には"abc\0\0\0"とかやってサイズを合わせて切り抜けるのかなと思います。

    キャンセル

-6

構造体の定義にはセミコロンつけるべきではない、ってことだと。
初期化じゃないんだから、とエラーメッセージはいってます

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/03/03 16:51

    セミコロンは必要です

    キャンセル

  • 2020/03/03 17:15

    エラーメッセージの意味が違うように思います

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.91%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る