_Pragma演算子を使ってみた。

以前から存在は知っていたけれど、一度も使ったことがないものというのは少なからずあります。
私にとって、_Pragma演算子もそのひとつでした。

_Pragma演算子というのはC99で導入された前処理演算子で、C++でもC++11から導入されました。
これは、もともとあった#pragma指令を演算子化したもので、うまく使えば結構便利です。

なぜ_Pragma演算子を使う機会がなかったかというと、ひとつは、最近はC++やC#を使う機会の方が多く、Cを使う機会があまりなかったことがあります。
もうひとつは、特定のコンパイラに依存するようなコードは可能な限り避けるようにしていたためです。

そんな私ですが、先日、ついに_Pragma演算子を使うことになったのです。

どういう状況だったかというと、WindowsとルネサスのRXマイコンでコードを共有化する必要があり、なおかつWindowsではOpenMPを使うというものです。
OpenMPでfor文を並列化するには次のように書かなければなりません。

#pragma omp parallel for
for (int i = 0; i < N; i++)
   ...

#pragma指令なので、OpenMPに対応しない処理系であれば通常無視されます。
たまたま同じ構文に合致する別の#pragma指令が存在する可能性もゼロではありませんが、まず考慮する必要はないでしょう。
少なくともRXマイコンのコンパイラにはありません。

ただ、そうはいっても、うるさい警告が出たりすることはありますし、何といっても気持ち悪いので、通常は次のようにします。

#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int i = 0; i < N; i++)
   ...

だんだんコードが汚くなってきましたね。
こういうのを、並列化するところにすべて入れていくのは気が滅入ります。

そこで_Pragma演算子の登場です。

#ifdef _OPENMP
#define OMP_PARALLEL_FOR _Pragma("omp parallel for")
#else
#define OMP_PARALLEL_FOR
#endif

のようにマクロ化しておけば、以降は

OMP_PARALLEL_FOR
for (int i = 0; i < N; i++)
   ...

と書くだけでよくなります。

何なら、

#ifdef _OPENMP
#define omp_parallel_for _Pragma("omp parallel for") for
#else
#define omp_parallel_for for
#endif

としておけば、

omp_parallel_for (int i = 0; i < N; i++)
   ...

のようにすることもできます。
これならかなり気楽に使えそうです。

マイコンのプログラミングでは、関数やオブジェクトをどのセクションに配置するかなど、#pragma指令を使う機会が多々あります。
以前はC99に対応していないために_Pragma演算子が使えないことが多かったのですが、現在では主要な処理系がC99に対応しています(C11はまだまだですが……)。
今後は_Pragma演算子を普通に使えそうですね。

Bookmark and Share