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

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

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

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

Q&A

6回答

2366閲覧

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

yuki23

総合スコア1448

C

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

3グッド

2クリップ

投稿2017/09/14 13:07

編集2017/09/15 13:08

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

c

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

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

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

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

c

1char string[] = "Hello, World";

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

c

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

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


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

LouiS0616, ikuwow, shimitei👍を押しています

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

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

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

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

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

guest

回答6

0

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

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
raccy

総合スコア21735

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

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

Harahira

2017/09/15 04:28

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

2017/09/15 13:15

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

2017/09/16 00:16 編集

K&Rにあるのはintやポインタなどについて{}に囲む話であって、文字列リテラルについてでは無いですよ。そもそも、"abc"は{'a', 'b', 'c', '\0'}と同じというのが本来のCですから、 char s[] = {"abc"}; は char s[] = {{'a', 'b', 'c', '\0'}}; の筈ですが、後者はコンパイルエラーになります。ということで、C99あたりで追加されたのではと思っているのですが、いかんせん、ISOがお高い。
raccy

2017/09/15 14:41

ということは、K&Rではわざと書かなかった可能性が高いかも知れません。それとも、K&Rでもどこかに書いてあって、見逃しているのか。 初版K&Rが出てから、Cの実装がみんな勝手に追加しまくって、収集付けようって産まれたのがC89だと聞いています。となると、誰かが、そんな実装してしまったとかでしょう。
guest

0

波括弧を省略してもよいという文法は、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

Harahira

総合スコア243

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

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

0

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

yohhoy

総合スコア6191

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

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

yohhoy

2017/09/15 17:28

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

0

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

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

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

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

投稿2017/09/14 13:35

編集2017/09/14 13:42
can110

総合スコア38268

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

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

yuki23

2017/09/14 14:29

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

2017/09/15 13:21

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

0

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

C

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

投稿2017/09/14 13:16

maisumakun

総合スコア145201

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

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

yuki23

2017/09/15 13:12

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

0

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

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

投稿2017/09/21 06:30

編集2017/09/21 06:34
a_saitoh

総合スコア702

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問