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

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

ただいまの
回答率

90.33%

  • C

    3991questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

「それを波括弧で囲んでもよい」は何の意味があるのか?

受付中

回答 6

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 1,587

yuki23

score 148

先日、以下のようなC言語のコードを見ました。

char string[] = {"Hello, World"};

最初は文字列の配列の初期化になるのかと思ったのですが、コンパイル結果などを見ると文字列の初期化として正常に受理されているのです。
よくよく調べてみると、JIS の C の言語規格に以下の文を発見しました。

6.7.8 初期化
スカラオブジェクトに対する初期化子は,単一の式でなければならない。それを波括弧で囲んでもよい。
文字型の配列は,単純文字列リテラルで初期化してもよい。それを波括弧で囲んでもよい。

つまり、前掲のコードは以下と同じだというのです。

char string[] = "Hello, World";

さらにスカラオブジェクトにも当てはまるので、以下も同じということです。

int num = 1;
int num = {1};

コンパイル結果がそうなるのはわかったのですが、規格としてこのように定められた理由が想像がつきません。
「波括弧で囲んでも良い」と決めることによって具体的に得することがあるのでしょうか。
それとも過去の規格・コードとの互換性か何かのために残されているだけなのでしょうか。


追記
可能であれば、文献的な根拠を示していただけるとありがたいです(議事録や規格策定者の発言など)。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 6

+5

そもそも、文字列だけでは無くて、通常の整数などでも同じで、

int 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)では

char pattern[] = "ould";

char pattern[] = {'o', 'u', 'l', 'd', '\0'};

と同値な簡略形としています。では、

char pattern[] = {"ould"};

char pattern[] = {{'o', 'u', 'l', 'd', '\0'}};

となるのかというと、後者はコンパイルエラーになります。普通の配列に対して余計な波括弧を足すことはできません。

ここからは私の単なる推測です。K&Rでは配列に対して、波括弧で囲んでリストを作るとしています。そして、文字配列については文字列リテラルでも初期化できるとしています。これを読んだCコンパイラの開発者が、何を思ったのか、「文字配列は配列だから、初期化子を波括弧で囲む必要があるけど、文字列リテラルも使えると言うことだから、波括弧の中で文字列リテラルを書けば良いんだ」と解釈したのでは無いでしょうか?つまり、char pattern[] = {"ould"};が正当であると。標準規格が定まる前の言語というのは、複数の実装が存在すると、それぞれが自分たちもそれができるという競争状態になります(JavaScriptが良い例です)。C言語もそのような状態であったため、うちのコンパイルでもできるとして広まっていったのかも知れません。ANSI制定にあたり、既存のコンパイラの実装状況の調査を行った時、既に普及している解析手法であったため、これは外せないとなったのが真相では無いかと思います。

なお、JIS規格はISO規格の翻訳に過ぎませんので、正確な情報を得たい場合にはISO規格を確認してください。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/09/15 13:28

    K&RのFirst Editionにも、8.6章に同一の記述があります。

    キャンセル

  • 2017/09/15 22:15

    ご回答ありがとうございます。K&R の初版に既にあるのであれば、 ANSI に聞いてもわからなそうですね。となればリッチーの発言を探すべきでしょうか。

    キャンセル

  • 2017/09/15 22:36 編集

    K&Rにあるのはintやポインタなどについて{}に囲む話であって、文字列リテラルについてでは無いですよ。そもそも、"abc"は{'a', 'b', 'c', '\0'}と同じというのが本来のCですから、

    char s[] = {"abc"};



    char s[] = {{'a', 'b', 'c', '\0'}};

    の筈ですが、後者はコンパイルエラーになります。ということで、C99あたりで追加されたのではと思っているのですが、いかんせん、ISOがお高い。

    キャンセル

  • 2017/09/15 23:23

    C89 のドラフトには既にあるようですね。 http://port70.net/~nsz/c/c89/c89-draft.html
    > An array of character type may be initialized by a character string literal, optionally enclosed in braces.

    キャンセル

  • 2017/09/15 23:41

    ということは、K&Rではわざと書かなかった可能性が高いかも知れません。それとも、K&Rでもどこかに書いてあって、見逃しているのか。

    初版K&Rが出てから、Cの実装がみんな勝手に追加しまくって、収集付けようって産まれたのがC89だと聞いています。となると、誰かが、そんな実装してしまったとかでしょう。

    キャンセル

+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


従って、初期化時の{ }の中には、ポインタ、算術形オブジェクト、文字列リテラルを置くことができ、以下のように記述することができます。

char a[] = "abc";
char a[] = { "abc" };
char a[] = { "abc" , };


また、K&Rの第一版では文法は以下のように定義されています。

init-declarator:
    declarator
    declarator initializer

initializer:
    = expression
    = { initializer-list }
    = { initializer-list , }

initializer-list:
    expression
    initializer-list, initializer-list
    { initializer-list } 


従って、同様に、以下のように記述することができます。

char a[] = "abc";
char a[] = { "abc" };
char a[] = { "abc" , };


また、文法上は以下のように記述できるかもしれません。

char 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


この頃は、初期化時に=を用いず、以下のように記述したようです。

char a[] "abc";
char a[] { "abc" };

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

配列の初期化子との釣り合い、だと思います。

char str[] = { 'H', 'e', 'l', 'l', 'o', '\0' };

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/09/15 22:12

    すみません、ちょっとよくわかりませんでした。どの辺りが釣り合いが取れているのでしょうか?

    キャンセル

+1

可能であれば、個人の憶測ではなく、文献的な根拠を示していただけるとありがたいです(議事録や規格策定者の発言など)。

インターネット上でざくっと調べた限り、文献的な根拠が見つかりませんでした。
そのような場合は、このような場で聞くより一次情報の提供者に問い合わせるのが最善かと思います。

一次情報への問い合わせ先はざくっと調べてすぐに見つかりました。
本工業標準調査会:FAQ(よくある質問)目次

個人的には、憶測含めて皆さんの意見を伺ってみたいという気持ちがありますが。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/09/14 23:29

    「可能であれば――していただけるとありがたいです」←この文章は命令ではありませんし、必要条件でもありません。そのままの意味で受け取ってください。

    キャンセル

  • 2017/09/15 22:21

    はい。了解してます。
    ただ、せっかく窓口もあるので、まずは正面突破でJISに聞いてみるのも良いかと。
    多分上位組織にたらいまわしにされるにしても、通信費以外はかからないと思います。
    でも、もしかしたらこの場ならショートカットして情報が得られるかな(チラッという気もしましたので
    > 個人的には、憶測含めて皆さんの意見を伺ってみたいという気持ちがありますが。
    と回答に加えました。

    キャンセル

+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/16 02:28

    FYI: JIS規格票の「それを波括弧で囲んでもよい」は、ANSI/ISO Standardでは "optionally enclosed in braces" が対応します。

    キャンセル

0

根拠はないですが、コンパイラが楽だから(いちいちチェックしてエラーにする方が手間がかかる)ではないでしょうか。
初期化の処理に関しては、スカラ変数を配列で要素数が1の場合の初期値で初期化しても問題ないので。

昔のコンパイラは今とは比べものにならない少ないメモリ量CPU速度で動いていたので言語仕様に変なクセをもたらしたりしてます。PASCALとかにも見られます。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

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

  • C

    3991questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。