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

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

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

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

Q&A

6回答

11361閲覧

C言語の.cファイルと.hファイルに違いはありますか?

退会済みユーザー

退会済みユーザー

総合スコア0

C

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

2グッド

1クリップ

投稿2018/07/13 07:08

他の言語では外部ファイルも同じ拡張子のソースコードでそれを読みこむのがありますよね。
C言語で拡張子が違くなっているのは何故ですか?

kazuyakazuya, yohhoy👍を押しています

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

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

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

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

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

guest

回答6

0

まずC言語と他の言語を比較してみる。すると最近の他の言語にはモジュールという物があり(詳細割愛)、ほかのモジュールを読み込むための構文が用意されている。モジュールの場合、外部公開するか否かを指定する(通常exportとかexternとかそんなキーワードを使う)ことで、他のモジュールからそのモジュールが読み込めるようになる。

C(そしてC++)ではどうかというとそんな高尚なものは存在しない。あるのは#includeというプリプロセッサマクロで、こいつはただの自動コピペマシーンだ。指定したファイルの中身をそっくりそこにコピペする。

すると困ったことがあって、複数の翻訳単位からincludeされることを想定していないファイルを読み込んでしまうと定義が複数出来上がりリンカーで衝突する。これはまずい。

解決策は

  1. 宣言のみを集めたファイルを作ってそれをincludeする
  2. inlineキーワードを利用して定義が複数出来上がっても同一のものなら衝突しないよう指示する

となる。

ここでヘッダーファイルとは宣言のみを集めたファイルを一般に指す。定義がないことをわかりやすくするため、.hとか.hppとかいう拡張子を利用することが多い。

2の手法は昔のC(C89)だと標準規格では用意されていなかったため、いまでもC言語界隈ではマイナーな解決策だ。しかしC++界隈ではtemplateの存在や名前マングルの問題からヘッダーオンリーライブラリと呼ばれる、2の手法を利用してヘッダーに実装をすべて書いてあるライブラリが流行している。

で、結局ヘッダーファイルとは何だったのか?歴史的変遷ののち、現在では#includeで読み込まれることを想定しているファイル、となる。そしてこれらに対して.hとか.hppとかいう拡張子を利用することが常識である。

投稿2018/07/13 08:39

編集2018/07/13 08:41
yumetodo

総合スコア5850

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

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

0

拡張子が別れているのは、両者ともC言語のソースコードではあるものの、使い方が違うからです。コンパイラやmakeなどは拡張子の使い分けを前提に動いていますので、違う拡張子にするのであれば手動設定する必要が出てきます。

  • .cファイル…関数や変数の定義を行う。基本的に同じ定義が重複するとリンクできないので、.cファイルを#include対象とすることは通常ない。
  • .hファイル…関数や変数、型の宣言を行う。呼ぶ各箇所で宣言が必要になるので、#includeを使って取り込む(なお、コンパイル前に処理されるマクロや、暗黙を含めinlineな関数、テンプレートなどについては、ヘッダで定義まで行って、そのまま複数ファイルで#includeしても問題ありません)。

他の言語での事例ですが、JavaやC#はコンパイル後のファイル自体が型情報を持っているためそのままコンパイラで処理ができ、ヘッダーは不要です。一方、C言語の場合は「型情報はソースコード内から読み取る」ということになっているので、ソースコードに#includeする形のヘッダーが必要になります。

また、PerlやPHPなどのスクリプト言語は型定義と実装を分けませんので、ヘッダーファイルという概念は存在しません。

投稿2018/07/13 08:15

編集2018/07/13 08:27
maisumakun

総合スコア145183

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

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

0

大体、他の人の書かれた通りなんですが、C言語の場合、歴史を無視できないじゃないかと。
確かに関数の宣言は大切ではありますが、初期の Cでは、宣言無しで使われると引数不明、戻り値 int とみなされていた。それよりもそれぞのソースファイルで共通に参照される 定数とか、別個に定義すると間違えるので、共通ファイルに置かれたじゃないですか?
今時のシステムでは、沢山のファイルを参照してなんて容易ですが、C言語は1990年よりも前だったかと。そして当時でも最新とは言えないシステムで作られたので、他のファイルを参照するにしても指定したファイルのみにした方が、効率が良い、、そんな発想ではないかと思います。(アセンブラ...)

それを今でも引きずっているのが、C言語でしょう。その系譜にありながら、使い勝手向上したのが、Java とか、C#

拡張子については他の人も書かれているように、共通化しておけば、分かり易く使い良い。(特に make ファイルで参照する時に、.c.o なんて定義すれば、かなり省略した書き方ができる)

投稿2018/07/13 13:57

pepperleaf

総合スコア6383

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

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

0

C 言語では、「関数の使用は宣言の後でなくてはならない」という制限があります。
関数 func() を使うに、func() の定義自体を行って宣言しておかなくてはなりません。
※main() は例外です

しかしこれを常に行うのは不可能(ライブラリ関数はソースがありませんからね)なので、前方宣言という機能があります。
関数の型(呼び出しパラメータの数と型、戻り値の型)だけを先に定義して、実装は後回しにするという方法です。これだと、実装の位置に関わらず宣言さえ正しければうまくコンパイルとリンクが行われます。ライブラリ関数の場合はコンパイルがなく、リンクの時点で実装がうまく結合されます。

この宣言のために使われるのが、ヘッダファイル(*.h)です。


前方宣言がなくてもコンパイル・リンクができるような言語もあります。逆に前方宣言を禁止している(必ず実態が利用の前に必要)ことで、コンパイル速度を稼ぐ言語もあります。

投稿2018/07/13 09:05

tacsheaven

総合スコア13703

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

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

pepperleaf

2018/07/13 11:38

> ※main() は例外です いや、main()は、(システム以外から)一般的に呼び出される事が無いからでしょう。
guest

0

こんにちは。

物事を分かりやすくするための習慣です。
複数の .c ファイルから#includeされるファイルには、 .h との拡張子を付ける習慣です。
これにより、そのソースを読む人は理解が捗ります。
ですので、守る必要はないですが、理由もなく守らないとそのソースを見る人を無駄に混乱させるため嫌がられます。

投稿2018/07/13 07:37

Chironian

総合スコア23272

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

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

退会済みユーザー

退会済みユーザー

2018/07/13 07:57

では他の言語ではそうなっていないのは何故でしょうか
Chironian

2018/07/13 08:14

別にC言語の方式が唯一無二なベストな方法というわけではないからと思います。 個人的にはヘッダ・ファイルを手で書く必要があるのは嬉しくはないです。他の一部の言語のように自動でexportしてくれると嬉しいです。でも、互換性維持の観点からそれはかなり難しそうな気がします。
退会済みユーザー

退会済みユーザー

2018/07/13 08:18

なにいってんのかわかんね
退会済みユーザー

退会済みユーザー

2018/07/13 08:19

他の言語は手で書かないのか 自動でexportって何 互換性?何のとこ?
episteme

2018/07/13 11:11

.h に [1] extern int add1(int x); .c に [2] int add1(int x) { return x+1; } とか書くやないですか。 そーすっとint add1(int x)が都合2回現れる。 ヘッダの要らない言語では[2]をコンパイルしたときに[1]に相当する"関数を使うひとのための情報(メタ・データとか言う)"を自動生成(export)するですよ。こんなCコンパイラを作ることも可能ですが、それはあくまでコンパイラ・メーカが独自にやることで、他のコンパイラに食わすときはやっぱヘッダが必要。互換性がないので。
guest

0

違いは無いと言えば無いですね。
.h.c以外の拡張子でも、中身がテキスト形式でC言語の構文で書かれていればコンパイルは可能です。
実際、過去に上記以外の拡張子のソースコードが含まれているプロジェクトで仕事したこともあります。
ただ、コンパイル対象のファイルをMakeFile等に列挙する際に ファイル名.拡張子 とひとつずつ書くよりも
「このフォルダの下の.c全部」と書いた方が楽なので普通は拡張子は揃えます。

ちなみにですが、普通は.hのファイルはコンパイル対象ではありません。
C言語ではxxxx.cというファイルをコンパイルしてxxxx.objのようなオブジェクトファイルを生成し、最後にそれらオブジェクトファイルと必要なライブラリファイルをリンクして実行ファイルを生成します。
先日知人がVisualStudioでxxxx.cからxxxx.hにリネームした後で再度xxxx.cを新規作成した際、xxxx.hがコンパイル対象になってしまいトラブっていました。
(xxxx.hxxxx.cの両方がxxxx.objの生成元となってしまい、後勝ちで上書かれてしまっていた)

投稿2018/07/13 07:41

編集2018/07/13 07:42
illusionist

総合スコア62

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

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

illusionist

2018/07/13 08:36 編集

C言語の#includeは他の言語のimport等のように高度なものではなくて、「『#include ファイル名』と書かれた位置にそのファイルの内容をガバっとコピペしてからコンパイルする」程度の意味です。 なので、#includeする対象のファイルも拡張子はなんでも良いです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

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

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

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問