関数へのポインターの出力(回答編)
question:1185077855
回答が 1 件しか付かなくて残念。しかし、コメント欄への書き込みも含めて、printf 系関数で変換指定子"%p"を使う方法しか出なかったので、やはり関数へのポインターを void へのポインターへ常に変換できると思っている人は多いのではないかと思われる。
CプログラミングFAQ―Cプログラミングのよく尋ねられる質問 (アジソン ウェスレイ・トッパン 情報化学シリーズ)
4.13
質問: 包括的な汎用ポインタ型は何か。関数へのポインタを void * に突っ込んだらコンパイラにしかられた。
回答: “包括的な汎用ポインタ型”は存在しない。void * に保障されていることはオブジェクト(すなわちデータ)を指すポインタを格納できることだけだ。関数ポインタを void * に変換することは移植性が高くない。(マシンによっては関数ポインタは非常に大きい。どのデータポインタよりも大きい。)
まあ、今時のマシンなら実際変換できる処理系は多いのだろうけど、変換できない場合にも使える方法(プログラム)を考えてみた。
ただし、次の 2 点の制限がある。
fptostr.c
#include <limits.h> #include <string.h> #include <stdio.h> #if (CHAR_BIT & 3) != 0 # error error: fptostr requires (CHAR_BIT & 3) == 0 to be compiled #endif #define FUNCPTR_DIGITINBYTE (CHAR_BIT>>2) typedef int (*funcptr_t)(); #define FUNCPTR_STRSIZE (2+sizeof(funcptr_t)*FUNCPTR_DIGITINBYTE) #define FUNCPTR_BYTETOSTR(cary,ci,c,di,sp) \ do { \ c = cary[ci]; \ for ( di = 0; di < FUNCPTR_DIGITINBYTE; ++di ) { \ *sp = xdigits[c & 0xf]; \ c >>= 4; \ --sp; \ } \ } \ while ( 0 ) int fptostr(funcptr_t p, char str[], size_t len) { static const char *xdigits = "0123456789abcdef"; const int bom = 1; const int is_little_endian = *(const char *)&bom == 1; unsigned char cary[sizeof(p)]; unsigned char c; char *sp; int ci, di; if ( !str || len <= FUNCPTR_STRSIZE ) return -1; memcpy(cary, &p, sizeof(p)); sp = str; *sp = '0'; ++sp; *sp = 'x'; sp = str + FUNCPTR_STRSIZE; *sp = '\0'; --sp; if ( is_little_endian ) { for ( ci = 0; ci < sizeof(p); ++ci ) { FUNCPTR_BYTETOSTR(cary, ci, c, di, sp); } } else { for ( ci = sizeof(p)-1; ci >= 0; --ci ) { FUNCPTR_BYTETOSTR(cary, ci, c, di, sp); } } return 0; } int main() { char fpstr[FUNCPTR_STRSIZE+1]; static const funcptr_t fps[] = { (funcptr_t)main , (funcptr_t)printf , (funcptr_t)fptostr , NULL }; int i; printf("FUNCPTR_DIGITINBYTE = %d\n", FUNCPTR_DIGITINBYTE); printf("FUNCPTR_STRSIZE = %d\n", FUNCPTR_STRSIZE); for ( i = 0; fps[i]; ++i ) { printf("----\n"); printf("%%p => %p\n", (const void *)fps[i]); if ( fptostr(fps[i], fpstr, sizeof(fpstr)) != 0 ) return 1; printf("fptostr => %s\n", fpstr); } return 0; }
実行例(i386/FreeBSD 6.2/gcc 3.4.6)
FUNCPTR_DIGITINBYTE = 2 FUNCPTR_STRSIZE = 10 ---- %p => 0x8048660 fptostr => 0x08048660 ---- %p => 0x80483b0 fptostr => 0x080483b0 ---- %p => 0x804852c fptostr => 0x0804852c
実行例(i686/CYGWIN_NT-5.1/gcc 3.4.4)
FUNCPTR_DIGITINBYTE = 2 FUNCPTR_STRSIZE = 10 ---- %p => 0x40118b fptostr => 0x0040118b ---- %p => 0x401310 fptostr => 0x00401310 ---- %p => 0x401050 fptostr => 0x00401050
実行例(i686/Windows XP/Visual Studio 2005)
FUNCPTR_DIGITINBYTE = 2 FUNCPTR_STRSIZE = 10 ---- %p => 00401160 fptostr => 0x00401160 ---- %p => 00401219 fptostr => 0x00401219 ---- %p => 00401000 fptostr => 0x00401000