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

Joseph Halfmoon

アセンブルで止める-Sオプションとか、コンパイルで止める-cオプションの前に、プリプロセスで止める-Eオプションがあったの忘れてました。-Eオプション、多分、今までに使ったこと無かったかも。やってみるとね、まあ使わなかったのにも一理?ありな感じがあり。あまり複雑なプリプロセスしないもんね。触らずに済む方が平和?

※動作確認に Windows11 WSL2上のUbuntu 20.04 LTS を使用しています。gccのバージョンは9.4.0です。

今回の実験につかうソース

自分、ヘッダファイルの#includeとか条件コンパイルの#if関係を除けば、#define文は定数とか、ごく簡単なマクロ程度でお茶を濁しています。Cのマクロでも結構すごいことやってる人もいるみたいですが、Cのマクロは所詮文字列の置き換え、C++のテンプレートのようにコンパイル終わったときには計算完了みたいな過激な?世界とは違いますな。

それもあって、プリプロセスだけでコンパイルに入らずに止める -E オプション、使ったことが無かったかも知れんです。プリプロセッサのマクロ展開やらなにやらを深く追わねばならない事態が無かった、ということでしょうか。お気楽。昔的には、cのプリプロセッサ、cppがファイルを読んでプリプロセスして出力し、それをコンパイラccに渡すという段取りだったです。ですが最近のccはプリプロセッサをかねているので、最初のパスでプリプロセスを2回目のパスでコンパイルをしているみたいっす。知らんけど。

さて、今回実験に使うソースは、多少複雑めなマクロが無いとつまらないので以下の別シリーズ記事で扱ったものといたしました。

ソフトな忘却力(32) NCURSES、New Cursesライブラリを使ってみる

なんといっても以下の getmaxyxのところで、ちょっと引っかかったからです。

#include <ncurses.h>

int main()
{
        int row, col;

        initscr();
        printw("Hello World !!!\n");
        getmaxyx(stdscr, row, col);
//以下省略

あれ、変数 rowとcolに値を代入する筈なのに、&row、&colじゃないじゃん?と一瞬引っかかりましたが、getmaxyxはマクロで、マクロ内で展開した結果row=チョメチョメ、col=チョメチョメというコードに展開されておるのだ、と理解しました。

インクルードしているヘッダファイルから追いかけて getmaxyx の定義を調べればそれで済む話です。いつもはそうしてます。しかし今回は、せっかくの-Eオプションにて、実際、どのように展開されているのか実地検分とな。

-Eオプション、クセが強い

-Sオプションや-cオプションの例からすると、途中で止めた場合cのソースファイルと同じファイル名で拡張子だけが .s とか .o とかのファイルが自動生成される筈だと。それで、以下のようにしてみました。

$ gcc -E ncursesHello2.c

プリプロセス結果が画面上を流れて終わりました。割と複雑なライブラリをとりこんでいるので、結構結果が長いです。所望のところを grep するなり、全体をlessするなりしないとダメなようです。とりあえず以下でファイルに落として観察しました。

$ gcc -E ncursesHello2.c >optionE.txt

そこから上記のソースの問題部分を探しました。getmaxyx でサーチすればいいじゃん、と思いましたが。うまく行きません。既に getmaxyx はマクロ展開されて消えておるぞよ、ということにようやく気付きました。ソースコードのファイル名と行番号が諸所に記されているので、それを手がかりにすれば良いのですが、メンドイです。それにこの行番号のコメント?が以外にクセもの。これがあるおかげで展開されたマクロが「ぶつ切り」状態で、人間可読ではあるものの、読みずらいったらありゃしません(個人の感想です。)こんな感じ。optionEgetmaxyx

コンパイラ様はこんなコードを読んでコンパイルしているのね。機械らしいといえば機械らしいデス。

上記を見るに、stdscrがNULLであるのか否か3項演算子で確認して、NULLでなければstdscr構造体の_maxyメンバに+1したものをrowに代入する、と。分かるけれども、まったく(人間的な)直観働きませんな。

因みにヘッダファイルで見れば getmaxyxの定義が以下に。

そして内部でさらに呼ばれている getmaxyの定義は以下に。getmaxyDefiniton

_maxyメンバを格納している構造体の定義が以下に。Struct

正直、プログラムを書いているときには、ヘッダファイルの定義を読んだ方がずっとわかりやすいと思います。何かマクロ展開の過程で思ったようにプロセスされなくて、異なる値が入っていた、とかいう事態である場合は -E オプションの方が良いかな~。

積極的に使いたい感じはしなかったのだけれど、知ってしまうと使いたくなるのだよな~。無理して変なマクロ書くなよ、自分。

オプション沼(7) gccに -static オプション、できたファイルはデカいのよ。 へ戻る

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