オプション沼(9) gccの-Dオプション、意外な使い方もあり?私は人生複雑にしたくないケド

Joseph Halfmoon

前回はプリプロセスで止め、コンパイルに進まない-Eオプションでした。今回もプリプロセッサ関係のオプション続けます。-Dオプションっす。よく使うやつ?そんなの知ってる。でも改めて取り組んでみると「新たな世界が開ける」ような気がしないでもないです(個人の感想デス。)まあ、人生複雑にしたくなければ深みにハマらん方が良い?

※動作確認に 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システムズ殿の以下のページを参考にさせていただきました。

C言語の高度なマクロ機能を活用したプログラミング

さすが組み込み業界の大立者、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の方は、文字列を取り出してます。

こういう結果をみて、つい、あれもやりて~、これも試したいなどと妄想すると深みにハマりそうで怖いデス。どうする?

オプション沼(8) gccの-Eオプション、プリプロセスのUnder the Hood? へ戻る

オプション沼(10) gccの-Eオプションを活用する? -dM、-dN、-dDオプション へ進む