先日、以下のようなC言語のコードを見ました。
c
1char string[] = {"Hello, World"};
最初は文字列の配列の初期化になるのかと思ったのですが、コンパイル結果などを見ると文字列の初期化として正常に受理されているのです。
よくよく調べてみると、JIS の C の言語規格に以下の文を発見しました。
6.7.8 初期化
スカラオブジェクトに対する初期化子は,単一の式でなければならない。それを波括弧で囲んでもよい。
文字型の配列は,単純文字列リテラルで初期化してもよい。それを波括弧で囲んでもよい。
つまり、前掲のコードは以下と同じだというのです。
c
1char string[] = "Hello, World";
さらにスカラオブジェクトにも当てはまるので、以下も同じということです。
c
1int num = 1; 2int num = {1};
コンパイル結果がそうなるのはわかったのですが、規格としてこのように定められた理由が想像がつきません。
「波括弧で囲んでも良い」と決めることによって具体的に得することがあるのでしょうか。
それとも過去の規格・コードとの互換性か何かのために残されているだけなのでしょうか。
追記
可能であれば、文献的な根拠を示していただけるとありがたいです(議事録や規格策定者の発言など)。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答6件
5
そもそも、文字列だけでは無くて、通常の整数などでも同じで、
C
1int x = {0};
としてもCとしては間違っていません。
さて、これらがいつ頃から産まれたか、それを探るには聖典「プログラミング言語C」(通称K&R)を確認する必要があるでしょう。K&RはC言語の開発者※であるプライアン・カーニハンとデニス・リッチーの共著であり、C言語とは何かを述べた名著です。これを読まずしてC言語を語ることはできません。
※ なお、カーニハンによるとC言語はリッチーが全て設計したとのことです。
このK&Rですが、最初の初版とANSI規格(C89)準拠の第二版の二つがあります。特に初版は、ANSIとして規格化される前の貴重な情報です。ただ、残念ながら初版は持っていないので確認できませんでしたので、第二版、つまりANSI規格準拠のバージョンについて述べます。
本文において、宣言および初期化子について述べているのは「2.4 宣言」と「4.9 初期化」の所です。しかし、ここでは波括弧で囲んでも良いとの記述は見受けられませんでした。
しかし、付録の部分の「A8.7 初期化」では下記のように述べています。
ポインタあるいは算術型のオブジェクトの初期知識は**(大カッコで囲まれていることもある)**単一の式である。(以下略)
-- 「プログラミング言語C」p.273 太字は引用者による。
つまり、int
などについては普通に囲むことはANSI規格の時点で認められており、カーニハンとリッチーとしては想定通りだったようです。ただし、この後の文字列リテラルによる文字配列に関する部分ではこの注意書きのような記述はありません。
※ Harahinaさんの情報によると初版でも上の文言はそのままあるようです。
ということですが、yuki23さんの情報によると、ANSI(C89)の時点では文字列リテラルを用いた初期化においては波括弧でも囲んでもよいとなっていたとのことです。ですが、K&Rにはそのような記述が無い事から、カーニハンとリッチーはそれが許されるとは想定してなかった可能性が高いです。
そもそもK&R(第二版 4.9 初期化 p.105)では
C
1char pattern[] = "ould";
を
C
1char pattern[] = {'o', 'u', 'l', 'd', '\0'};
と同値な簡略形としています。では、
C
1char pattern[] = {"ould"};
は
C
1char pattern[] = {{'o', 'u', 'l', 'd', '\0'}};
となるのかというと、後者はコンパイルエラーになります。普通の配列に対して余計な波括弧を足すことはできません。
**ここからは私の単なる推測です。**K&Rでは配列に対して、波括弧で囲んでリストを作るとしています。そして、文字配列については文字列リテラルでも初期化できるとしています。これを読んだCコンパイラの開発者が、何を思ったのか、「文字配列は配列だから、初期化子を波括弧で囲む必要があるけど、文字列リテラルも使えると言うことだから、波括弧の中で文字列リテラルを書けば良いんだ」と解釈したのでは無いでしょうか?つまり、char pattern[] = {"ould"};
が正当であると。標準規格が定まる前の言語というのは、複数の実装が存在すると、それぞれが自分たちもそれができるという競争状態になります(JavaScriptが良い例です)。C言語もそのような状態であったため、うちのコンパイルでもできるとして広まっていったのかも知れません。ANSI制定にあたり、既存のコンパイラの実装状況の調査を行った時、既に普及している解析手法であったため、これは外せないとなったのが真相では無いかと思います。
なお、JIS規格はISO規格の翻訳に過ぎませんので、正確な情報を得たい場合にはISO規格を確認してください。
投稿2017/09/14 15:36
編集2017/09/16 00:31総合スコア21741
2
波括弧を省略してもよいという文法は、K&Rの第一版より前、UNIX V6(1975年リリース)頃からあったと考えられます。
K&Rの第二版では文法は以下のように定義されています。
init-declarator: declarator declarator = initializer initializer: assinment-expression { initializer-list } { initializer-list , } initializer-list: initializer initializer-list, initializer
従って、初期化時の{ }の中には、ポインタ、算術形オブジェクト、文字列リテラルを置くことができ、以下のように記述することができます。
C
1char a[] = "abc"; 2char a[] = { "abc" }; 3char a[] = { "abc" , };
また、K&Rの第一版では文法は以下のように定義されています。
init-declarator: declarator declarator initializer initializer: = expression = { initializer-list } = { initializer-list , } initializer-list: expression initializer-list, initializer-list { initializer-list }
従って、同様に、以下のように記述することができます。
C
1char a[] = "abc"; 2char a[] = { "abc" }; 3char a[] = { "abc" , };
また、文法上は以下のように記述できるかもしれません。
C
1char a[] = { { "abc" } };
また、K&Rの第一版より前のUNIX V6の頃のCでは文法は以下のように定義されています。
init-declarator: declarator declarator initializer initializer: constant { constant-expression-list } constant-expression-list: constant-expression constant-expression , constant-expression-list constant-expression: expression
この頃は、初期化時に=を用いず、以下のように記述したようです。
C
1char a[] "abc"; 2char a[] { "abc" };
投稿2017/09/15 19:37
総合スコア245
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
1
K&R 第1版から該当記述がある(私は持っていません)とのことですから、委員会制に移る前にはすでに事実上の仕様となっていたと考えられます。よって"議事録や規格策定者の発言"の存在は期待できないでしょう。たぶん。
C言語仕様が「なぜそうなっているのか」を示す公式な文書として、"Rationale for C"が公開されています。
同文書§3.5.7/6.7.8 Initializationより引用:
Various implementations have parsed aggregate initializers with partially elided braces differently.
The Standard has reaffirmed the top−down parse described in K&R. Although the construct is allowed, and its parse well defined, the C89 Committee urges programmers to avoid partially elided initializers because such initializations can be quite confusing to read.
QUIET CHANGE IN C89
Code which relies on a bottom−up parse of aggregate initializers with partially elided braces will not yield the expected initialized object.
直接的にあなたの疑問に答えるものではありませんが、推測のヒントにはなるでしょう。
投稿2017/09/15 17:25
総合スコア6191
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

1
可能であれば、個人の憶測ではなく、文献的な根拠を示していただけるとありがたいです(議事録や規格策定者の発言など)。
インターネット上でざくっと調べた限り、文献的な根拠が見つかりませんでした。
そのような場合は、このような場で聞くより一次情報の提供者に問い合わせるのが最善かと思います。
一次情報への問い合わせ先はざくっと調べてすぐに見つかりました。
本工業標準調査会:FAQ(よくある質問)目次
個人的には、憶測含めて皆さんの意見を伺ってみたいという気持ちがありますが。
投稿2017/09/14 13:35
編集2017/09/14 13:42総合スコア38352
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

1
配列の初期化子との釣り合い、だと思います。
C
1char str[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
投稿2017/09/14 13:16
総合スコア146538
0
根拠はないですが、コンパイラが楽だから(いちいちチェックしてエラーにする方が手間がかかる)ではないでしょうか。
初期化の処理に関しては、スカラ変数を配列で要素数が1の場合の初期値で初期化しても問題ないので。
昔のコンパイラは今とは比べものにならない少ないメモリ量CPU速度で動いていたので言語仕様に変なクセをもたらしたりしてます。PASCALとかにも見られます。
投稿2017/09/21 06:30
編集2017/09/21 06:34総合スコア702
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/09/15 04:28
2017/09/15 13:15
2017/09/16 00:16 編集
2017/09/15 14:23
2017/09/15 14:41