以前から存在は知っていたけれど、使ったことがないものというのは少なからずあります。私にとって、_Pragma演算子もそのひとつでした。
_Pragma演算子というのはC99で導入された前処理演算子で、C++でもC++11から導入されました。これは、もともとあった#pragma指令を演算子化したもので、うまく使えば結構便利です。
なぜ_Pragma演算子を使う機会がなかったかというと、ひとつは、最近はC++やC#を使う機会の方が多く、C言語を使う機会があまりなかったことがあります。もうひとつは、特定のコンパイラに依存するようなコードは可能な限り避けるようにしていたためです。
そんな私ですが、ついに_Pragma演算子を使うときが来ました。
どういう状況だったかというと、WindowsとルネサスのRXマイコンでコードを共有化する必要があり、なおかつWindowsではOpenMPを使うというものです。OpenMPでfor文を並列化するには次のように書かなければなりません。
0 1 2 3 4 |
#pragma omp parallel for for (int i = 0; i < N; i++) ... |
pragma指令なので、OpenMPに対応しない処理系であれば通常無視されます。たまたま同じ構文に合致する別の#pragma指令が存在する可能性もゼロではありませんが、まず考慮する必要はないでしょう。少なくともRXマイコンのコンパイラにはありません。
ただ、そうはいっても、うるさい警告が出たりすることはありますし、何といっても気持ち悪いので、通常は次のようにします。
0 1 2 3 4 5 6 |
#ifdef _OPEN #pragma omp parallel for #endif for (int i = 0; i < N; i++) ... |
だんだんコードが汚くなってきましたね。こういうのを、並列化するところにすべて入れていくのは気が滅入ります。
そこで_Pragma演算子の登場です。
0 1 2 3 4 5 6 |
#ifdef _OPENMP #define OMP_PARALLEL_FOR _Pragma("omp parallel for") #else #define OMP_PARALLEL_FOR #endif |
のようにマクロ化しておけば、以降は
0 1 2 3 4 |
OMP_PARALLEL_FOR for (int i = 0; i < N; i++) ... |
と書くだけでよくなります。
何なら、
0 1 2 3 4 5 6 |
#ifdef _OPENMP #define omp_parallel_for _Pragma("omp parallel for") for #else #define omp_parallel_for for #endif |
としておけば、
0 1 2 3 |
omp_parallel_for (int i = 0; i < N; i++) ... |
と書くこともできます。これならかなり気楽に使えそうです。
マイコンのプログラミングでは、関数やオブジェクトをどのセクションに配置するかなど、#pragma指令を使う機会が多々あります。以前はC99に対応していないために_Pragma演算子が使えないことが多かったのですが、現在では主要な処理系がC99に対応しています(C11はまだまだですが……)。今後は_Pragma演算子を普通に使えそうですね。