LoginSignup
14
2

More than 5 years have passed since last update.

君の名は。 in C

Last updated at Posted at 2016-12-08

C言語 Advent Calendar 2016 が12/1以降なんとなく繋がっているので、役に立たない小ネタで2度目の参加です。

突然ですが

C言語のプログラム中の「マクロ(macro)1」と「関数(function)」に対して、全く 同じ名前 を使うことは可能でしょうか?

例えば NAME という名前のマクロと NAME という名前の関数を 同時に定義し、それぞれを 呼び分ける ことはできるでしょうか?

無理?

と思った?実現可能です。というか、無理だったらはなからこんな記事書きませんよね。

括弧()の力を使うことで、下記ソースコードのように記述できます。カギとなるのは B)関数の定義 と、D)関数の呼び出し の記述方法でしょうか。

yourname.c
#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を利用した技法もあります。

yourname2.c
#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年に流行った映画に似ていますね。見てないけど。



  1. 本記事で扱うマクロは、厳密には「関数形式マクロ(function-like macro)」と呼ばれる形式のものです。通常の「関数」との混同を避けるため、本文中では単に「マクロ」と表記します。 

14
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
2