C言語のインクルードガードはpragma onceを使う
インクルードガードとは、ソースコードの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 の衝突のリスクがありません。
関連項目
ツイート