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

提供: C言語入門
移動: 案内検索
スポンサーリンク

インクルードガードとは、ソースコードの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 の衝突のリスクがありません。
  • ヘッダファイルを作成する場合は、無限ループを防ぐために、インクルードガードを記載します。
  • メジャーな処理系では、対応していますが、もし、非常に古いコンパイラを使う場合は、機能しないかもしれません。

関連項目




スポンサーリンク