読者です 読者をやめる 読者になる 読者になる

C言語で関数名の文字列を取得する方法

C言語で関数名を取得する方法だが,普通にC言語をコンパイルするとリンクの時点で関数名のシンボルは削除されるため,関数名を取得するにはちょっと小細工が必要になる.
自分なりにググってまとめたので書く.

方法

__func__を使う

C言語には定義済みマクロというのがあって,__LINE__, __func__などがこれに当たる,この2つはそれぞれ実行中の行と実行中の関数名に置換される.
当たり前だが,このマクロは実行中の関数の中で使わなければならない.
よって,デバッグで関数トレースとかするのには使えるが,関数ポインタから文字列取得したいとかいうのは無理.
しかも,GCCが先行実装して,その後,C99で標準化されたらしいので,VCとかGCCじゃないC処理系使ってる人は注意して使ったほうがいい.

サンプル

#include <stdio.h>

void hoge(void)
{
  printf("%s\n", __func__);
}

int main(int argc, const char *argv[])
{
  hoge();
  
  return 0;
}

出力

hoge
マクロの#演算子を使う

C言語のマクロだけで使える#演算子は引数の頭に#をつけると引数の両端にダブルクオーテーションがついて,引数が文字列になる.
でも,たかがマクロなので単純置換されるだけ,つまりサンプルプログラムを例に取るとaddress2str(hoge+1-1)とすると"hoge+1-1",foo=hoge;address2str(foo)とすると"foo"になってしまう.

サンプル

#include <stdio.h>

#define address2str(func) #func

void hoge(void)
{
}

int main(int argc, const char *argv[])
{
  printf("%s\n", address2str(hoge));
  
  return 0;
}

出力

hoge
GCCのrdynamicオプションとGCC拡張dladdrをつかう

GCCのrdynamicオプションはコンパイル後もシンボル情報を残し,動的ライブラリかつ,実行可能なファイルを出力するオプションである.
一方,dladderはdlfcn.hに定義されているGNU拡張で,ポインタからシンボルに関する情報を得るための関数である.
dlfcn.h自体は動的ライブラリを扱うためのPOSIXで定義されているライブラリなので,dladderを使うにはdlfcn.hのインクルード前に#define __USE_GNUする必要がある.
もちろんGCC拡張なので,他のC処理系で使えない.

サンプル

#include <stdio.h>
#define __USE_GNU
#include <dlfcn.h>

void hoge(void)
{
}

int main(int argc, const char *argv[])
{
  Dl_info dli;

  dladdr(hoge, &dli);
  printf("%s\n", dli.dli_sname);
  
  return 0;
}
% gcc sample.c -ldl -rdynamic
hoge

結論

GCCを使っているなら3番目のGCC拡張のが確実に動くので,これが一番いいと思う.