わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

関数ポインタの値は?

今朝の語録の1番目に,関数ポインタを取り上げましたが,その値をprintfで知ることができるのかな,と考えて,コードを書いてみました.

/* fncpnt.c */
#include <stdio.h>

int main(void)
{
  printf("main: %p\n", main);
  printf("printf: %p\n", printf);
  return 0;
}

「%p」はあまり使いませんが,ポインタ値を教えてくれます.
それでは,コンパイルと実行.

$ gcc -o fncpnt fncpnt.c
$ ./fncpnt
main: 0x80483a4
printf: 0x80482d8

値が出てきました.めでたしめでたし.
なのですが,もう少しチェックを.

$ gcc -Wall -o fncpnt fncpnt.c
$ gcc -Wall -std=c89 -o fncpnt fncpnt.c

問題なし.
ではなかった,こういうときは「-pedantic細かいことにうるさい」をつけるのでした.

$ gcc -Wall -std=c89 -pedantic -o fncpnt fncpnt.c
fncpnt.c: In function 'main':
fncpnt.c:5: 警告: format '%p' expects type 'void *', but argument 2 has type 'int (*)(void)'
fncpnt.c:6: 警告: format '%p' expects type 'void *', but argument 2 has type 'int (*)(const char * __restrict__)'

「-std=c89」を抜いても,同じ結果でした.
ここの警告を訳すと,「%pにはvoid *型の値をとりたいのだが,第2引数はそうではない」というもの.
ではキャストを使って,関数ポインタの値をvoid *に変換してみましょう.

/* fncpnt.c */
#include <stdio.h>

int main(void)
{
  printf("main: %p\n", (void *)main);
  printf("printf: %p\n", (void *)printf);
  return 0;
}

あとは,先ほどと同じように.

$ gcc -o fncpnt fncpnt.c
$ ./fncpnt
main: 0x80483a4
printf: 0x80482d8
$ gcc -Wall -pedantic -o fncpnt fncpnt.c
fncpnt.c: In function 'main':
fncpnt.c:5: 警告: ISO C forbids conversion of function pointer to object pointer type
fncpnt.c:6: 警告: ISO C forbids conversion of function pointer to object pointer type

警告を訳すと,「ISO Cでは,関数ポインタをオブジェクトポインタの型に変換することを禁じている」.
関数ポインタと通常のポインタは,ポインタの種類が違うということでしたか.了解しました.
コンパイラは以下の通りですが,たいていのgccでも,同じ結果になると思います.

$ gcc --version
gcc (GCC) 4.1.2 (Gentoo 4.1.2)