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

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

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

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

Q&A

解決済

2回答

7843閲覧

C言語で2重インクルードが発生する理由

redhat98

総合スコア236

C

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

0グッド

1クリップ

投稿2017/04/19 23:26

こんにちは

C/C++の入門サイトを見ていると、ヘッダファイルを2重インクルードするのはNG。インクルードガードを使いましょうと記載されています。

仕事でプログラムを書いているので、インクルードガードの仕組みや使い方は普通に理解できます。
わからないと点は、java/C#はインクルードガードという概念自体が無いのに、C言語は何故こんな面倒な事をやらなくちゃいけなくなったのかという点です。

私が考えた所によると

  1. C99とかで言語仕様が決まっているから
  2. コンパイラの技術が低い時代に作られたプログラムが残っているので、互換性が~という理由
  3. そもそも、コンパイラ的に対応ができない

あたりかなと思いました。

何故、今の時代になっても、C言語では2重インクルードが発するんですか?

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

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

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

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

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

guest

回答2

0

ベストアンサー

3択の中から選ぶとすれば、「3 そもそも、コンパイラ的に対応ができない」です。

というのも、そもそも#includeはプリプロセッサへの指令で、コンパイラがソースを読む段階では消えてなくなっています。プリプロセッサは機械的に文字展開するだけですので、重複していても(インクルードガードがない限り)全く気にしません。

投稿2017/04/19 23:47

maisumakun

総合スコア145121

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

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

0

以下、推測が入っています。間違い等があればご指摘下さい。

初期のCが開発されたのは1972年です。当時は今よりもパーサ(構文を解析するプログラム)について今ほど発展はしておらず、また、最初のCのコンパイラはC以外で作る必要がありました。ただ、かなり初期にセルフホスティングコンパイラはできていた模様です。しかし、C自体がまだ貧弱であり、コンパイラを作るにも限界がありました。

初期のCコンパイラ: mortdeus/legacy-cc - GitHub
紹介文: 本の虫: デニス・リッチーによって書かれた最初のCコンパイラーがGitHubで公開

何を言いたいかというと、Cはなるべく構文を単純かつ機械的に処理できるようにする必要があったと言うことです。;で文の終了が明示しなければならなかったり、コメントは/* */しか使えなかったり(いまは//も使える)など現代の言語に比べると機械的に処理しやすいかが重点に置かれています。

さて、この初期のCにはプリプロセッサがありません。コンパイラ部分はなるべく単純にしたかったため、他のファイルを見に行くという処理をコンパイラにさせることが難しかったのだと思われます。そこで、プリプロセッサという全く別の機能をCに追加することで、他ファイルの読み込み、つまり、ヘッダファイルの読み込みというものの考え方を導入しました。

プリプロセッサは単純な文字列の置換です。いえ、当時の技術では単純な文字列の置換しかできなかったのです。#includeで分離したヘッダファイルをその部分に置換することはできるようになりましたが、その方法は原始的で、本当に単純に置換するだけです。そして、どのファイルを既に読み込んだのかと言うことをプリプロセッサで記録しながら進めると言うことを実装することすらできませんでした。そのため、二重インクリュード問題が発生することになります。そこで考えられたのが、#ifndef等による分岐でのインクリュードガードだったと思われます。

その後CはANSIやISOの規格(C89/C90)になり、最新はC11です。ANSIである程度整理されましたが、最新C11であっても、この単純な仕組みは維持された形になっています。また、現代でもC89/C90で書かれたプログラムが残っているため、いますぐ無くなることはないでしょう。

なお、現代のコンパイラはかなり発展しており、当時のプリプロセッサができなかったすでに読み込んだファイルを覚えておくと言うことはできるようになっています。非標準の方法ですが#pragma onceを使うと、インクリュードは一度のみになります。メジャーなほぼ全てのコンパイラで対応済みですので、現代のコンパイラができないと言うことではありません。

投稿2017/04/20 22:20

raccy

総合スコア21733

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問