前回はプリプロセスで止め、コンパイルに進まない-Eオプションでした。今回もプリプロセッサ関係のオプション続けます。-Dオプションっす。よく使うやつ?そんなの知ってる。でも改めて取り組んでみると「新たな世界が開ける」ような気がしないでもないです(個人の感想デス。)まあ、人生複雑にしたくなければ深みにハマらん方が良い?
※「オプション沼」投稿順 index はこちら
※動作確認に Windows11 WSL2上のUbuntu 20.04 LTS を使用しています。gccのバージョンは9.4.0です。
-Dオプション、言わずと知れた奴
コンパイラに渡すコマンドライン上で、マクロが定義されていることにしてくれる -D オプションは、まさにコンパイル時オプションの代表選手、ちょっと複雑なビルドともなれば目にしないことはありませぬ。普通は、
gcc -D OPTIONSWITCH チョメチョメ。。。
などとしてコンパイルする先のソース内で以下のようにプリプロセッサの#if, #ifdef, #ifndef などで受ける、というのが定石じゃないかと思います。知らんけど。
#ifdef OPTIONSWITCH //オプションスイッチの時に処理する仕事
上記例のような場合マクロの値としては、OPTIONSWITCHには定数1であると。しかしま、「マクロ名=チョメチョメ」みたいな形式で値を代入することもできるんでありますな。
今回実験に使うソース
以下が今回実験に使うソースです。短いですが、#if文だらけであまりお近づきになりたくない感じのもの。その中で1か所躓いたところがあり。マクロの文字列化演算子#のところです。IARシステムズ殿の以下のページを参考にさせていただきました。
さすが組み込み業界の大立者、IARシステムズ殿であります。感謝(蛇足ながら、IARシステムズ殿のホームページ右下にある「クルーエンジニア・モード」、クールっす。よいしょ。)
#include <stdio.h> #define TO_STR(x) #x #define TO_STR_WRAPPER(x) TO_STR(x) int main (int argc, char const *argv[]) { #if OPD printf("(#if)OPD=%d\n", OPD); #else printf("(#if)OPD NOT DEFINED.\n"); #endif #ifdef OPD printf("(#ifdef)OPD=%s\n", TO_STR_WRAPPER(OPD)); #else printf("(#ifdef)OPD NOT DEFINED.\n"); #endif #ifndef OPD printf("(#ifndef)OPD NOT DEFINED.\n"); #endif }
実験結果
今回の-Dオプションは、「コンパイルするときには終わっている」話なので毎度ビルドを繰り返して確かめてみます。メンドイ。
まずは、-Dオプションを付けずに上記のソース optD.c をビルドして動かしたときの様子。
$ gcc -g -O0 optD.c $ ./a.out (#if)OPD NOT DEFINED. (#ifdef)OPD NOT DEFINED. (#ifndef)OPD NOT DEFINED.
予定通り、#ifでも#ifdefでも#ifndefでも条件不一致側に倒れているようです。
つづいて、-Dオプションでマクロ名のみのとき
$ gcc -g -O0 -D OPD optD.c $ ./a.out (#if)OPD=1 (#ifdef)OPD=1
流石に#ifndefが成立することはなく、#if、#ifdefともに条件一致側です。値は1とな。しかしソースをご覧いただければ分かるとおり、#ifの方は定数扱いで%d、#ifdefの方は文字列扱いで%sで変換してます(文字列取り出すのに#演算子が登場するのでありますが。)
つづいて -Dオプションに数字を与えてみます。こんな感じ。
$ gcc -g -O0 -D OPD=2 optD.c $ ./a.out (#if)OPD=2 (#ifdef)OPD=2
=2などとすれば、値は2となると。当たり前だろ~。
では足し算を表す文字列を与えてみたらばどうよ?
$ gcc -g -O0 -D OPD="1+3" optD.c $ ./a.out (#if)OPD=4 (#ifdef)OPD=1+3
ここにいたりて #if と #ifdef の結果が分かれましたな。#if の方はあくまで定数値として、プリプロセッサ内で 1+3 の計算がなされ、4だと。一方 #ifdef の方は、文字列として取り出していすrので 1+3 だと。ううむ。
ではもろに文字列与えてみたらどうよ?こんな感じ。
$ gcc -g -O0 -D OPD=ABC optD.c $ ./a.out (#if)OPD NOT DEFINED. (#ifdef)OPD=ABC
文字列 ABC を #if は定数値とみなすことはなく、定数でないものは自分の条件ではないと拒絶しておりますな。一方 #ifdefの方は、文字列を取り出してます。
こういう結果をみて、つい、あれもやりて~、これも試したいなどと妄想すると深みにハマりそうで怖いデス。どうする?