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

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

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

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

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

コンパイル

コンパイルとは、プログラミング言語のテキストソース(ソースコード)をコンピュータ上で実行可能な形式(オブジェクトコード)に変換することをいいます

ビルド

ソースコードを単体で実行可能なソフトウェアへ変換する過程をビルド(build)と呼びます

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

5回答

3697閲覧

ビルドのときにヘッダファイルと静的リンクライブラリファイルが必要になる理由

Nawta

総合スコア4

C

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

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

コンパイル

コンパイルとは、プログラミング言語のテキストソース(ソースコード)をコンピュータ上で実行可能な形式(オブジェクトコード)に変換することをいいます

ビルド

ソースコードを単体で実行可能なソフトウェアへ変換する過程をビルド(build)と呼びます

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/05/27 07:27

lib.*.aのようなバイナリファイル(静的リンクライブラリ)について、ビルドの際にこれらのファイルを指定すると同時に対応するヘッダファイルを別途指定する必要があるのはなぜですが?
リンカで複数のバイナリファイルを作るのが普通になった理由としては「逐一同じコード(ライブラリのコード部分)をコンパイルしているのが勿体ない」と言うのがあると思うのですが、なぜ与える必要があるのでしょうか。
どうせ後からライブラリの部分はリンクされるので、ヘッダファイルを与えてしまってコンパイルさせるのは無駄ではありませんか?
https://kamino.hatenablog.com/entry/c%2B%2B-principle-of-build-library
ここのブログを読ませていただいて思いました。

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

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

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

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

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

episteme

2020/05/27 07:31

ヘッダ無しにどうやってコンパイルするんです? # リンク時にはヘッダ要らんけど...
guest

回答5

0

質問の趣旨を捉えられているかどうかちょっと自信がないのですが、

ライブラリファイルはリンクに必要な情報を持っているはずなのに、なぜ同様な情報を持った「ヘッダファイル」を別扱いにしてインクルードとかいうオマジナイをしなきゃいけないのか、ということでしょうか。

であるなら、私の思うところでは、
C言語が古いものだから
です。

Cが生まれたのは1970年代前半。そのころのコンピュータ事情を考えてみて下さい。
ソースにオブジェクトにライブラリ、そんな沢山のファイルを一気にまとめて置けるストレージも、それを受け入れるメモリも、一般で手に入るようなコンピュータは持っていませんでした。(そもそもコンピュータが「一般」で手に入ったかどうか)。そんな環境でCは頑張ったのです。関数や変数は、その情報だけあれば中身全部がソースになくても外部結合という形で部分毎に処理出来るようにしました。プリプロセス/コンパイル/アセンブル/リンクを各ステージ分けることで、各ステージごとのメモリ使用量も切り詰められるでしょう。
コンピュータの能力が足りなければ、そう、プログラマが代わりに苦労すればいいのです。複数のソースで共用する情報は、人間がコンパイル時に必要なものだけ切り出してヘッダファイルにしましょう。リンカはコンパイル結果のオブジェクトとライブラリだけ寄せ集めれば出来るようにしました。ライブラリの情報とヘッダファイルの同期? そんなのプログラマの責任で管理して下さい。
そんな匠の心を今に伝えているのが「ヘッダファイル」なのではないかと。

今どきの言語は、関連するファイルを全部どこかにまとめておけば、ファイル間で共有すべき情報は処理系が勝手に抽出してくれるのが普通ですよね。時代は変わったものです。

投稿2020/05/27 13:09

thkana

総合スコア7639

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

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

Nawta

2020/05/27 17:50

なるほど!! なんでヘッダにメソッドも何も全部かけるのにソースコードと分ける必要があるんだろうとすごく思っていたのですが、そうですね、コンパイル時にとりあえず必要な情報だけ書いとくといった用途にするためにはヘッダファイルという概念を作るのが一番良い気がします! 納得できました。ありがとうございます!!!
guest

0

えっと、OSがどうやって実行可能ファイルを実行しているかですよね。OSはローダによって実行可能ファイルをメインメモリに読み込みます。そのときローダはプログラムが正しく動作するようにプログラムを「改変」します。C言語はコンパイラとリンカによって実行可能ファイルを生成することは分かっていますよね。コンパイラが生成するファイルのことをオブジェクトファイルと呼ぶことも。要はこういうことです。

ソースプログラム(.c) → [コンパイラ] → オブジェクトファイル(.o) → [リンカ] → 実行可能ファイル → [ローダ] → 実際に動作するコード

リンカとローダはシンボルを編集します。オブジェクトファイルと実行可能ファイルと実際に動作するコードはほとんど同じものです。何が違うかというと、実際に動作するコード以外はシンボルという「断片をつなぎ合わせるのに必要な情報」を持っているということです。

C言語はソースファイル単位で機械語を生成します。特殊なビルドチェーンでなければリンクのときに最適化を行いません。なぜそうするかというとコンパイルという処理がとても重いためです。コンパイルはソースファイルを読み込んで機械語に変換する作業です。できればこの作業は小分けで行いたいのです。したがってオブジェクトファイルというファイル形式が存在するのです。コンパイラは関数名をシンボルに変換します。ソース内で他のソースファイルの関数を呼び出している場合は「これこれのシンボルください」という情報に変換されます。

ヘッダファイルは複数のソースプログラムで関数宣言を共有するためのものです。これはC言語に型という概念が存在するために必要です。他のソースプログラムの関数を呼び出すとき、正しく呼び出すためにはその関数のインターフェースが必要になります。ここでいう「インターフェース」はJava言語のインターフェースと似ています。Javaのインターフェースはクラスによって実装されます。Cのヘッダファイルはソースプログラムによって実装されるのです。

静的リンクライブラリがどうして存在するかというと、コンパイル済みのコード片が必要だからであり、静的リンクライブラリはリンカによってオブジェクトファイルを集約したものになります。ここで再びリンカを使うことによってユーザーが書いたオブジェクトファイルと静的リンクライブラリをリンクさせることができます。

どうしてC言語ではヘッダファイルと静的リンクライブラリの2種類を用意しなければならないかということですが、C言語がアセンブリ言語の代替として登場したというのもあります。オブジェクトファイルはC言語だけでなくアセンブリコードからも生成されます。そこで静的リンクライブラリはアセンブリ言語と互換性のある部分であり、ヘッダファイルは純粋にC言語固有の部分なのです。

投稿2020/06/10 16:17

編集2020/06/10 16:46
anndonut

総合スコア667

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

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

0

すでに出ていますが、関数の呼び出しにはその関数の戻り地・引数を定義した宣言が必要になります。
また、構造体・クラスを使用するならば、それらの定義も必要になります。

ライブラリ側のヘッダには、それらが記述されています。
もしヘッダファイルを提供しないとなれば、自分で記述しなければなりません。

例えば、以下の一般的なWin32のプログラム。

c

1#include <windows.h> 2 3LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 4{ 5 switch (msg) { 6 case WM_DESTROY : 7 PostQuitMessage(0); 8 break; 9 10 default : 11 return DefWindowProc(hWnd, msg, wParam, lParam); 12 } 13 return 0l; 14} 15 16int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR pszCmdLine, int nCmdShow) 17{ 18 WNDCLASSEX wcx; 19 HWND hWnd; 20 MSG msg; 21 22 wcx.cbSize = sizeof(WNDCLASSEX); 23 wcx.style = CS_HREDRAW | CS_VREDRAW; 24 wcx.lpfnWndProc = WindowProc; 25 wcx.cbClsExtra = 0; 26 wcx.cbWndExtra = 0; 27 wcx.hInstance = hInst; 28 wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION); 29 wcx.hCursor = LoadCursor(NULL, IDC_ARROW); 30 wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 31 wcx.lpszMenuName = NULL; 32 wcx.lpszClassName = _T("MainWndClass"); 33 wcx.hIconSm = NULL; 34 if (RegisterClassEx(&wcx) == 0) { 35 return 1; 36 } 37 38 hWnd = CreateWindowEx(0, _T("MainWndClass"), _T("Hello"), WS_OVERLAPPEDWINDOW, 39 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 40 NULL, NULL, NULL, NULL); 41 if (hWnd == NULL) { 42 return 1; 43 } 44 ShowWindow(hWnd, nCmdShow); 45 UpdateWindow(hWnd); 46 47 while (GetMessage(&msg, NULL, 0, 0)) { 48 TranslateMessage(&msg); 49 DispatchMessage(&msg); 50 } 51 52 return msg.wParam; 53} 54

この中の、

c

1#include <windows.h>

は、Microsoftが提供しているヘッダファイルです。
もしMicrosoftがヘッダファイルを提供しないとなれば、この一文の代わりに、以下のコードを自分で書く必要があります。

c

1 2#define NULL ((void *)0) 3#define _T(n) L##n 4typedef long long LRESULT; 5#define CALLBACK 6struct HWND__ { int unused; }; typedef struct HWND__ * HWND; 7typedef unsigned int UINT; 8typedef unsigned long long WPARAM; 9typedef long long LPARAM; 10typedef unsigned long DWORD; 11typedef unsigned short WORD; 12typedef long LONG; 13typedef void *LPVOID; 14#define WM_DESTROY 0x0002 15void PostQuitMessage(int); 16LRESULT DefWindowProcW(HWND, UINT, WPARAM, LPARAM); 17#define DefWindowProc DefWindowProcW 18#define APIENTRY 19struct HINSTANCE__ { int unused; }; typedef struct HINSTANCE__ *HINSTANCE; 20typedef wchar_t * LPTSTR; 21typedef LRESULT ( *WNDPROC)(HWND,UINT,WPARAM,LPARAM); 22struct HICON__ { int unused; }; typedef struct HICON__ *HICON; 23struct HBRUSH__ { int unused; }; typedef struct HBRUSH__ *HBRUSH; 24struct HMENU__ { int unused; }; typedef struct HMENU__ *HMENU; 25typedef HICON HCURSOR; 26typedef const wchar_t * LPCWSTR; 27typedef struct tagWNDCLASSEXW { 28 UINT cbSize; 29 UINT style; 30 WNDPROC lpfnWndProc; 31 int cbClsExtra; 32 int cbWndExtra; 33 HINSTANCE hInstance; 34 HICON hIcon; 35 HCURSOR hCursor; 36 HBRUSH hbrBackground; 37 LPCWSTR lpszMenuName; 38 LPCWSTR lpszClassName; 39 HICON hIconSm; 40} WNDCLASSEXW,*PWNDCLASSEXW,*NPWNDCLASSEXW,*LPWNDCLASSEXW; 41typedef struct tagPOINT { 42 LONG x; 43 LONG y; 44} POINT,*PPOINT,*NPPOINT,*LPPOINT; 45typedef struct tagMSG { 46 HWND hwnd; 47 UINT message; 48 WPARAM wParam; 49 LPARAM lParam; 50 DWORD time; 51 POINT pt; 52} MSG,*PMSG,*NPMSG,*LPMSG; 53typedef struct tagPOINT { 54 LONG x; 55 LONG y; 56} POINT,*PPOINT,*NPPOINT,*LPPOINT; 57typedef WORD ATOM; 58ATOM RegisterClassExW (const WNDCLASSEXW *); 59#define RegisterClassEx RegisterClassExW 60HWND CreateWindowExW(DWORD dwExStyle,LPCWSTR lpClassName,LPCWSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam); 61#define CreateWindowEx CreateWindowExW 62#define WS_OVERLAPPEDWINDOW (0x00000000l | 0x00C00000l | 0x00080000l | 0x00040000l | 0x00020000l | 0x00010000l) 63#define CW_USEDEFAULT ((int)0x80000000) 64#define CS_HREDRAW 0x0002 65#define CS_VREDRAW 0x0001 66HICON LoadIconW(HINSTANCE hInstance,LPCWSTR lpIconName); 67#define LoadIcon LoadIconW 68HCURSOR LoadCursorW(HINSTANCE hInstance,LPCWSTR lpCursorName); 69#define LoadCursor LoadCursorW 70#define IDI_APPLICATION ((LPSTR)((ULONG_PTR)((WORD)(32512)))) 71#define IDC_ARROW ((LPSTR)((ULONG_PTR)((WORD)(32512)))) 72#define COLOR_WINDOW 5 73typedef int WINBOOL; 74WINBOOL ShowWindow(HWND hWnd,int nCmdShow); 75WINBOOL UpdateWindow(HWND hWnd); 76WINBOOL GetMessageW(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax); 77#define GetMessage GetMessageW 78WINBOOL TranslateMessage(const MSG *lpMsg); 79LRESULT DispatchMessageW(const MSG *lpMsg);

どうですか、あなたはこれを書く気になりますか?
私は、書くんじゃなかったと後悔してます(笑)

(チクショウ、「gcc -E」でプリプロセッサ展開して一ファイルにすれば楽に書けるだろうとたかを括った)

投稿2020/05/27 14:22

katsuko

総合スコア3471

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

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

katsuko

2020/05/27 14:34

あ、一個ミス見つけた。 さらに言えば、Win32APIは静的ライブラリじゃないか。まぁ、理屈は同じですし、勘弁してください…。
Nawta

2020/05/27 17:55

そうですね、C++系ではライブラリのファイルにはファイル間の依存関係などが保存されていないなど他の方の回答にもあったように、ヘッダファイルの必要性が礼を通じてすごくわかりました。理解が深まりました。ありがとうございます!!
guest

0

ベストアンサー

補足的回答を。

ライブラリの配布方法はいくつかあります。

ヘッダーオンリーにしてしまう場合

この場合は利用者は単にヘッダーファイルをgit submoduleなりcmakeなり自力で引っ張ってきてinclude pathを通してincludeすれば利用できます。

C++のtempalteを多用するライブラリによく見られます。

利用しやすい半面、ビルド速度が遅くなりがちです。

ヘッダーオンリーにしない場合

ソースコードを配布する場合

ビルドのためのスクリプト(autotoolsの設定とかcmakeの設定とか)くらいはつけるけど、
をそのまま配布する場合。

利用者は予めビルドする必要があり、やや利用しにくいです。著名なソフトウェアならライブラリ作者ではなく第三者がビルドして公開している場合もあります。pacman, apt, yumなどの
パッケージマネージャなんかはその例です。またビルドスクリプトをパッケージにする例(vcpkgなど)もあります。

ビルド済のライブラリを配布する場合

静的/動的リンクライブラリとヘッダーファイルを配布します。

利用者はビルドする必要がありませんが、自分の環境向けのものが配布されていない場合はあります。またライブラリ製作者は必要な環境すべてに対してビルドしておかなければなりません。

ソースコードを開示する必要がないので、プロプライエタリソフトウェアなどに見られる他、利用者の多い環境向けに配布しているOSSもあります。

投稿2020/05/27 08:54

yumetodo

総合スコア5850

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

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

Nawta

2020/05/27 17:45

ものすごくスッキリわかりました!メソッドのソースを見られたくない場合もあるのは何となくわかるので腑に落ちました!ありがとうございます
guest

0

どうせ後からライブラリの部分はリンクされるので、ヘッダファイルを与えてしまってコンパイルさせるのは無駄ではありませんか?

いえ、ヘッダファイルがないと型情報が得られないため、コンパイルができません。

Javaや.NET Frameworkのような環境では、型情報もコンパイル後のオブジェクトファイルに保持されていますが、CやC++の場合は(デバッグ用は別として)コンパイル後のライブラリは実行コードだけで型情報が残らないので、ヘッダが必要です。

投稿2020/05/27 07:34

maisumakun

総合スコア145184

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

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

Nawta

2020/05/27 07:48

なるほど、そうだったのですね。 ではヘッダファイルだけを配布する形式からオブジェクトファイル(静的リンクライブラリファイル)も配布する形式に移り変わったのはなぜなのですか? ヘッダファイルだけ配布すれば十分ならばそっちの方がシンプルで良いのではと思ってしまいます。
ozwk

2020/05/27 07:59 編集

> Nawtaさん 一応ですけど、ヘッダファイルとソースコードは意味が違いますよ? 質問文に書いてあるブログの3.1も「ソースコードの配布」であって「ヘッダファイルの配布ではないです」
退会済みユーザー

退会済みユーザー

2020/05/27 08:07

一応ヘッダファイルだけで提供されているクラスライブラリも見たことはあります。 WTLがそうだったかな。
episteme

2020/05/27 08:31

↑ぜーんぶtemplate(or inline)だったらそうなりますわね。
Nawta

2020/05/27 17:57

ライブラリのソースファイルとヘッダファイルを分けるということが分かっていませんでした。。。今理解できました。みなさんご回答ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問