「C言語のインクルードガードはpragma onceを使う」の版間の差分

提供: C言語入門
移動: 案内検索
(関連項目)
 
(同じ利用者による、間の2版が非表示)
行1: 行1:
'''インクルードガード'''とは、ソースコードのinclude処理が重複して発生することを防ぐためのものです。C言語では、define/ifndefのプリプロセッサディレクティブを利用して、インクルードガードを実現していました。[[C99]]では、新たに '''pragma once''' が追加されました。
+
'''インクルードガード'''とは、ソースコードのinclude処理が重複して発生することを防ぐためのものです。C言語では、define/ifndefのプリプロセッサディレクティブを利用して、インクルードガードを実現していました。処理系の拡張により '''pragma once''' が追加されました。
  
 
'''読み方'''
 
'''読み方'''
行10: 行10:
 
'''C言語'''の'''プリプロセッサ'''(cpp) は、'''プリプロッサディレクティブ''' の '''include''' が出現するたびに、'''ヘッダファイル'''(.h)を展開しようとします。
 
'''C言語'''の'''プリプロセッサ'''(cpp) は、'''プリプロッサディレクティブ''' の '''include''' が出現するたびに、'''ヘッダファイル'''(.h)を展開しようとします。
  
'''インクルードガード'''は、ヘッダファイルの相互インクルードで'''無限ループ'''に陥ることを防ぐことができます。
+
'''インクルードガード'''は、ヘッダファイルの相互インクルードで'''無限ループ'''に陥ることを防ぐことができます。ただし、defineの重複を排除することができないため、思わぬ副作用を産んでしまうこともありました。
 +
 
 
何度もインクルードすることによって、定義が重複してしまいますが、インクルードガードがあれば、定義を一度にすることができ、コンパイル時の処理量を減らすこともできます。
 
何度もインクルードすることによって、定義が重複してしまいますが、インクルードガードがあれば、定義を一度にすることができ、コンパイル時の処理量を減らすこともできます。
  
ここでは、ifndef/define のインクルードガードよりも便利になった [[C99]]で導入された '''pragma once''' を紹介します。
+
ここでは、ifndef/define のインクルードガードよりも便利になった '''pragma once''' を紹介します。
 
== 古いインクルードガードの実装例 ==
 
== 古いインクルードガードの実装例 ==
[[C99]]より前の時代では、インクルードガードは、以下の ifndef/define のプリプロセッサディレクティブを利用して実現していました。
+
古い時代では、インクルードガードは、以下の ifndef/define のプリプロセッサディレクティブを利用して実現していました。
 
<syntaxhighlight lang="c">
 
<syntaxhighlight lang="c">
 
/*
 
/*
行78: 行79:
 
'''Cコンパイラ'''  によって、'''インクルードガード'''は ifndef 形式が速い場合もあれば、pragma once が速いこともあるし、どちらもそんなに変わらないケースもあります。
 
'''Cコンパイラ'''  によって、'''インクルードガード'''は ifndef 形式が速い場合もあれば、pragma once が速いこともあるし、どちらもそんなに変わらないケースもあります。
 
== まとめ ==
 
== まとめ ==
* [[C99]]では、インクルードガードは '''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 の衝突のリスクがありません。
  • ヘッダファイルを作成する場合は、無限ループを防ぐために、インクルードガードを記載します。
  • メジャーな処理系では、対応していますが、もし、非常に古いコンパイラを使う場合は、機能しないかもしれません。

関連項目