C言語のインクルードガードはpragma onceを使う

提供: C言語入門
2016年1月9日 (土) 18:30時点におけるDaemon (トーク | 投稿記録)による版 (ページの作成:「'''インクルードガード'''とは、ソースコードのinclude処理が重複して発生することを防ぐためのものです。C言語では、define/ifnde...」)

(差分) ←前の版 | 最新版 (差分) | 次の版→ (差分)
移動: 案内検索
スポンサーリンク

インクルードガードとは、ソースコードのinclude処理が重複して発生することを防ぐためのものです。C言語では、define/ifndefのプリプロセッサディレクティブを利用して、インクルードガードを実現していました。C99では、新たに pragma once が追加されました。

読み方

pragma once
ぷらぐま わんす
インクルードガード
いんくるーどがーど
include guard
いんくるーどがーど

概要

C言語プリプロセッサ(cpp) は、プリプロッサディレクティブinclude が出現するたびに、ヘッダファイル(.h)を展開しようとします。

インクルードガードは、ヘッダファイルの相互インクルードで無限ループに陥ることを防ぐことができます。 何度もインクルードすることによって、定義が重複してしまいますが、インクルードガードがあれば、定義を一度にすることができ、コンパイル時の処理量を減らすこともできます。

ここでは、ifndef/define のインクルードガードよりも便利になった C99で導入された pragma once を紹介します。

古いインクルードガードの実装例

C99より前の時代では、インクルードガードは、以下の 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 が速いこともあるし、どちらもそんなに変わらないケースもあります。

まとめ

  • C99では、インクルードガードは pragma once を利用します。
  • define の衝突のリスクがありません。

関連項目




スポンサーリンク