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

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

新規登録して質問してみよう
ただいま回答率
85.48%
GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

コンパイラ

コンパイラは、プログラミング言語で記述したソースコードを、コンピュータの実行形式であるオブジェクトコードに変換するプログラムです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

4回答

1830閲覧

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

seiken

総合スコア4

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

コンパイラ

コンパイラは、プログラミング言語で記述したソースコードを、コンピュータの実行形式であるオブジェクトコードに変換するプログラムです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2020/03/03 07:13

編集2020/03/05 02:55

前提・実現したいこと

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

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

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

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

test.cpp: In function ‘int main()’: test.cpp:16:3: error: C99 designator ‘hoge’ outside aggregate initializer }; ^

該当のソースコード

C++

1struct foo { 2 char hoge[32]; 3}; 4 5union bar { 6 foo f; 7 foo g; 8}; 9 10int main() 11{ 12 bar a = { 13 .f = { 14 .hoge = "Hello world" 15 } 16 }; 17}

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

C++

1struct foo { 2 char hoge[32]; 3}; 4 5foo a = { 6 .hoge = "Hello world" 7};

試したこと

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

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

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

投稿2020/03/03 07:33

編集2020/03/03 07:34
fana

総合スコア11654

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

seiken

2020/03/03 07:49

回答ありがとうございます。 ご指摘の部分は、例えば3行目の';'ということですか? これを外すと、コンパイラは ``` Expected ';' after struct definition. ``` というエラーメッセージを出します。
fana

2020/03/03 07:52

(リンクと「指示付き初期化子」という言葉で答えたんで,まずはそこを見て欲しい…) 問題は main()内の(エラーメッセージもmain()の中だと言ってますよ) bar a = ... の部分で, .メンバ名 = 値 という書き方をしていることかと.
seiken

2020/03/03 07:57

すみません、コメントする回答を間違えていました。 はい、問題はmain()にあるのですが、GCCでは私が書いたような書き方はできない、ということなのかなと思っています。
fana

2020/03/03 08:13

> C99 designator ‘hoge’ outside aggregate initializer ざっくり,「そのC99の書き方,無理っす^^」ということかと.
seiken

2020/03/03 08:25

そ、そうですねえ。 ところが、fooの中のhogeがintであり、main()の中でhoge=1みたいに書くとコンパイルは通るのです。
yumetodo

2020/03/03 08:45

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

2020/03/03 08:53

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

2020/03/03 08:56 編集

↓コンパイル通りますね。。。 struct foo { int hoge[2]; }; union bar { foo f; foo g; ; int main() { bar a = { .f = { .hoge = {1,9} } }; }
guest

0

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/03 11:23

編集2020/03/03 11:29
raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

seiken

2020/03/03 16: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でもコンパイルできました。 どうでしょう、これで間違いなさそうなら、まとめを投稿してみます。
raccy

2020/03/04 10: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";`は動作だけでなく、初期化子の解釈の仕方そのもの(言わば文法)が異なるということ)
seiken

2020/03/05 02:43

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

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

c++

1struct foo { 2 char hoge[4]; 3}; 4 5int main() 6{ 7 foo a = { 8 .hoge = "abc" 9 }; 10}

これ↓はエラー

c++

1struct foo { 2 char hoge[5]; 3}; 4 5int main() 6{ 7 foo a = { 8 .hoge = "abc" 9 }; 10}

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

c++

1struct foo { 2 int hoge[2]; 3}; 4 5union bar { 6 foo f; 7 foo g; 8}; 9 10int main() 11{ 12 bar a = { 13 .f = { 14 .hoge = {1} 15 } 16 }; 17}

投稿2020/03/03 09:07

編集2020/03/03 09:15
Y.H.

総合スコア7914

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

seiken

2020/03/03 15:11

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

0

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

投稿2020/03/03 07:19

y_waiwai

総合スコア87749

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yumetodo

2020/03/03 07:51

セミコロンは必要です
fana

2020/03/03 08:15

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問