C言語 Advent Calendar 2016 が12/1以降なんとなく繋がっているので、役に立たない小ネタで2度目の参加です。
突然ですが
C言語のプログラム中の「マクロ(macro)1」と「関数(function)」に対して、全く 同じ名前 を使うことは可能でしょうか?
例えば NAME
という名前のマクロと NAME
という名前の関数を 同時に定義し、それぞれを 呼び分ける ことはできるでしょうか?
無理?
と思った?実現可能です。というか、無理だったらはなからこんな記事書きませんよね。
括弧()
の力を使うことで、下記ソースコードのように記述できます。カギとなるのは B)関数の定義 と、D)関数の呼び出し の記述方法でしょうか。
#include <stdio.h>
// A) マクロmacro_or_funcを定義する
#define macro_or_func(s) puts(s)
// B) 関数macro_or_funcを定義する
void (macro_or_func)(const char* s)
{
// C) マクロmacro_or_funcを呼び出す
macro_or_func(s);
}
int main()
{
// D) 関数macro_or_funcを呼び出す
(macro_or_func)("C");
}
特に B) はかなり特殊な書き方だと思います。私もStackOverflowの質問と回答を見るまでは知りませんでした。
いやぁ、C言語ってホントに奥が深いですねぇ。
ちなみに
2016/12/12追記: 括弧()
を使わない別解として、高度な革新的技術によるマクロPREVENT_MACRO_SUBSTITUTION
を利用した技法もあります。
#include <stdio.h>
#define PREVENT_MACRO_SUBSTITUTION
// A) マクロmacro_or_funcを定義する
#define macro_or_func(s) puts(s)
// B) 関数macro_or_funcを定義する
void macro_or_func PREVENT_MACRO_SUBSTITUTION(const char* s)
{
// C) マクロmacro_or_funcを呼び出す
macro_or_func(s);
}
int main()
{
// D) 関数macro_or_funcを呼び出す
macro_or_func PREVENT_MACRO_SUBSTITUTION("C");
}
C++言語向けのBoostライブラリでは、同等のBOOST_PREVENT_MACRO_SUBSTITUTION
マクロが提供されています。
こんな汚いテクニックがどこで必要なのか?と思われるかもしれませんが、一部の環境では役に立つこともあります。歴史的経緯もあるし仕方ないよね。うん。
あとがき
本記事で紹介した内容に実用性はほとんどないでしょう。よほど特殊な事情でもない限り、マクロ名と関数名には異なる名前をつけるべきです。
あと、タイトルは数十秒考えて適当につけました。2016年に流行った映画に似ていますね。見てないけど。
-
本記事で扱うマクロは、厳密には「関数形式マクロ(function-like macro)」と呼ばれる形式のものです。通常の「関数」との混同を避けるため、本文中では単に「マクロ」と表記します。 ↩