__func__で関数名にアクセスする
C99に、関数名にアクセスするための識別子__func__
が追加されました。デバッグやログをとる時に使います。なお、__func__
はマクロではなく、const char
型で定義されていますから、関数の引数にする場合は、型も合わせなければいけません。
『Cクイックリファレンス』14頁
関数名を表示する
__fucn__
を使って関数名を表示させてみます。
#include <stdio.h>
static void doNothing(void);
static int addInt(int x, int y);
int main(void)
{
printf("%s: %s()\n", __LINE__, __func__);
doNothing();
int ans = addInt(2, 3);
return 0;
}
static void doNothing(void)
{
printf("%d: %s()\n", __LINE__, __func__);
}
static int addInt(int x, int y)
{
printf("%d: %s()\n", __LINE__, __func__);
return x + y;
}
$ ./a.out
8: main()
19: doNothing()
24: addInt()
__func__
が呼ばれた行とそこの関数名が表示されました。
__func__の正体
__func__
の正体は、関数内で宣言された静的なchar
型の定数です(4.10 事前定義済み __func__ シンボルの関数名としての使用)。
コンパイルできませんが、次のようなイメージです。
static void usage(void) {
static const char __func__[] = "usage";
}
int main(void)
{
static const char __func__[] = "main";
return 0;
}
__func__
の正体が、char
型の定数配列だということが分かりました。ということは、関数の引数に渡したいときは、hoge(const char *str);
と、const
修飾子を忘れずにつけます。
#include <stdio.h>
static void showFuncName(const char *p);
int main(void)
{
showFuncName(__func__);
return 0;
}
static void showFuncName(const char *p)
{
puts(__func__);
}
関数化して実用的に
原始的なcat
コマンドを書いてみました。fopen()
で失敗してNULL
が返ってくると、その行番号と関数名が表示されます。普段は不要ですから-DEBUG
オプションをつけました。
#include <stdio.h>
#include <stdbool.h>
static void printNullError(int line, const char *func);
static bool openFile(FILE **fpp, char *fileName);
static void showTextFile(FILE *fp);
static void closeFile(FILE **fpp);
int main(int argc, char *argv[])
{
for (int i = 1; i < argc; i++) {
FILE *fp;
if(!openFile(&fp, argv[i])) {
continue;
}
showTextFile(fp);
closeFile(&fp);
}
return 0;
}
static void printNullError(int line, const char *func)
{
fprintf(stderr, "%d: %s(): NULL pointer exception\n",
line, func);
}
static bool openFile(FILE **fpp, char *fileName)
{
*fpp = fopen(fileName, "r");
if (*fpp == NULL) {
fprintf(stderr, "%s: No such file or directory\n", fileName);
#ifdef DEBUG
printNullError(__LINE__, __func__);
#endif
return false;
}
return true;
}
static void showTextFile(FILE *fp)
{
const int Max = 8;
char buf[Max];
while (fgets(buf,Max,fp) != NULL) {
fputs(buf, stdout);
}
}
static void closeFile(FILE **fpp)
{
fclose(*fpp);
}
openFile()
の引数に存在しないファイルを指定すると、NULL
が返ってくるため、行と関数名が表示されます。
$ echo '0123456789abcdefghijk' > hoge.txt
$ ./a.out hoge.txt fuga.txt
0123456789abcdefghijk
fuga.txt: No such file or directory
33: openFile(): NULL pointer exception