「C言語のインクルードガードはpragma onceを使う」の版間の差分
(ページの作成:「'''インクルードガード'''とは、ソースコードのinclude処理が重複して発生することを防ぐためのものです。C言語では、define/ifnde...」) |
(→関連項目) |
||
(同じ利用者による、間の3版が非表示) | |||
行1: | 行1: | ||
− | '''インクルードガード'''とは、ソースコードのinclude処理が重複して発生することを防ぐためのものです。C言語では、define/ | + | '''インクルードガード'''とは、ソースコードのinclude処理が重複して発生することを防ぐためのものです。C言語では、define/ifndefのプリプロセッサディレクティブを利用して、インクルードガードを実現していました。処理系の拡張により '''pragma once''' が追加されました。 |
'''読み方''' | '''読み方''' | ||
行10: | 行10: | ||
'''C言語'''の'''プリプロセッサ'''(cpp) は、'''プリプロッサディレクティブ''' の '''include''' が出現するたびに、'''ヘッダファイル'''(.h)を展開しようとします。 | '''C言語'''の'''プリプロセッサ'''(cpp) は、'''プリプロッサディレクティブ''' の '''include''' が出現するたびに、'''ヘッダファイル'''(.h)を展開しようとします。 | ||
− | '''インクルードガード'''は、ヘッダファイルの相互インクルードで'''無限ループ''' | + | '''インクルードガード'''は、ヘッダファイルの相互インクルードで'''無限ループ'''に陥ることを防ぐことができます。ただし、defineの重複を排除することができないため、思わぬ副作用を産んでしまうこともありました。 |
+ | |||
何度もインクルードすることによって、定義が重複してしまいますが、インクルードガードがあれば、定義を一度にすることができ、コンパイル時の処理量を減らすこともできます。 | 何度もインクルードすることによって、定義が重複してしまいますが、インクルードガードがあれば、定義を一度にすることができ、コンパイル時の処理量を減らすこともできます。 | ||
− | ここでは、ifndef/define のインクルードガードよりも便利になった | + | ここでは、ifndef/define のインクルードガードよりも便利になった '''pragma once''' を紹介します。 |
== 古いインクルードガードの実装例 == | == 古いインクルードガードの実装例 == | ||
− | + | 古い時代では、インクルードガードは、以下の ifndef/define のプリプロセッサディレクティブを利用して実現していました。 | |
<syntaxhighlight lang="c"> | <syntaxhighlight lang="c"> | ||
/* | /* | ||
行78: | 行79: | ||
'''Cコンパイラ''' によって、'''インクルードガード'''は ifndef 形式が速い場合もあれば、pragma once が速いこともあるし、どちらもそんなに変わらないケースもあります。 | '''Cコンパイラ''' によって、'''インクルードガード'''は ifndef 形式が速い場合もあれば、pragma once が速いこともあるし、どちらもそんなに変わらないケースもあります。 | ||
== まとめ == | == まとめ == | ||
− | * | + | * インクルードガードとは、includeディレクティブによる相互インクルードの無限ループを防ぐために利用されます。 |
+ | * C言語では、インクルードガードは '''pragma once''' を利用します。 | ||
* define の衝突のリスクがありません。 | * define の衝突のリスクがありません。 | ||
+ | * ヘッダファイルを作成する場合は、無限ループを防ぐために、インクルードガードを記載します。 | ||
+ | * メジャーな処理系では、対応していますが、もし、非常に古いコンパイラを使う場合は、機能しないかもしれません。 | ||
== 関連項目 == | == 関連項目 == | ||
+ | * [[C言語解説]] | ||
* [[C99]] | * [[C99]] | ||
<!-- vim: filetype=mediawiki | <!-- vim: filetype=mediawiki | ||
--> | --> |
2016年1月9日 (土) 21:01時点における最新版
インクルードガードとは、ソースコードのinclude処理が重複して発生することを防ぐためのものです。C言語では、define/ifndefのプリプロセッサディレクティブを利用して、インクルードガードを実現していました。処理系の拡張により pragma once が追加されました。
読み方
- pragma once
- ぷらぐま わんす
- インクルードガード
- いんくるーどがーど
- include guard
- いんくるーどがーど
目次
概要
C言語のプリプロセッサ(cpp) は、プリプロッサディレクティブ の include が出現するたびに、ヘッダファイル(.h)を展開しようとします。
インクルードガードは、ヘッダファイルの相互インクルードで無限ループに陥ることを防ぐことができます。ただし、defineの重複を排除することができないため、思わぬ副作用を産んでしまうこともありました。
何度もインクルードすることによって、定義が重複してしまいますが、インクルードガードがあれば、定義を一度にすることができ、コンパイル時の処理量を減らすこともできます。
ここでは、ifndef/define のインクルードガードよりも便利になった pragma once を紹介します。
古いインクルードガードの実装例
古い時代では、インクルードガードは、以下の ifndef/define のプリプロセッサディレクティブを利用して実現していました。
/* * include_guard.h * Copyright (C) 2016 kaoru <kaoru@localhost> */ #ifndef INCLUDE_GUARD_H #define INCLUDE_GUARD_H void foo(void); #endif /* !INCLUDE_GUARD_H */
これは、ちょっと、書くのが面倒ですね。
defineを利用した方法の問題点として、define が被ってしまうと、インクルードガードで定義が読み込めないといった副作用を及ぼし、コンパイルできないといった事象を引き起こすこともあります。宣言しているのに、宣言されたことにならない、といった場合は、defineの衝突を調査したほうが良いでしょう。
ソースコード
pragma_once.h
pragma once を利用した場合には、以下のようになります。
/* * pragma_once.h * Copyright (C) 2016 kaoru <kaoru@localhost> */ #pragma once void foo(void);
ifndef/define を利用していたときに比べて、コードが簡素になりました。これならdefineの衝突の心配もありません。
main.c
/* * main.c * Copyright (C) 2016 kaoru <kaoru@localhost> */ #include "pragma_once.h" #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { foo(); exit(EXIT_SUCCESS); } void foo(void) { puts("foo"); }
コンパイル
$ cc -I. -std=c99 main.c
実行例
$ ./a.out foo
コンパイラごとのパフォーマンス
Cコンパイラ によって、インクルードガードは ifndef 形式が速い場合もあれば、pragma once が速いこともあるし、どちらもそんなに変わらないケースもあります。
まとめ
- インクルードガードとは、includeディレクティブによる相互インクルードの無限ループを防ぐために利用されます。
- C言語では、インクルードガードは pragma once を利用します。
- define の衝突のリスクがありません。
- ヘッダファイルを作成する場合は、無限ループを防ぐために、インクルードガードを記載します。
- メジャーな処理系では、対応していますが、もし、非常に古いコンパイラを使う場合は、機能しないかもしれません。