有没有办法在ANSI C中打印指向函数的指针?当然这意味着你必须将函数指针强制转换为void指针,但看起来这是不可能的??
#include <stdio.h>
int main() {
int (*funcptr)() = main;
printf("%p\n", (void* )funcptr);
printf("%p\n", (void* )main);
return 0;
}
$ gcc -ansi -pedantic -Wall test.c -o test
test.c:在功能上 'main':
test.c:6:警告:ISO C 禁止转换函数指针 对象指针类型
test.c:7: 警告:ISO C禁止转换 函数指针指向对象 类型
$ ./test
0x400518
0x400518
它“有效”,但非标准......
答案 0 :(得分:44)
执行此操作的唯一合法方法是使用字符类型访问构成指针的字节。像这样:
#include <stdio.h>
int main() {
int (*funcptr)() = main;
unsigned char *p = (unsigned char *)&funcptr;
size_t i;
for (i = 0; i < sizeof funcptr; i++)
{
printf("%02x ", p[i]);
}
putchar('\n');
return 0;
}
将函数指针作为void *
或任何非字符类型(dreamlax's answer does),是未定义的行为。
构成函数指针的那些字节实际上意味着与实现有关。例如,它们只能表示函数表的索引。
答案 1 :(得分:5)
使用可以绕过警告/错误的联合,但结果仍然(很可能)是未定义的行为:
#include <stdio.h>
int
main (void)
{
union
{
int (*funcptr) (void);
void *objptr;
} u;
u.funcptr = main;
printf ("%p\n", u.objptr);
return 0;
}
你可以使用if语句来比较两个函数指针(例如printf ("%i\n", (main == funcptr));
)来测试它们是否相等(我知道这完全违背了目的并且很可能无关紧要),但是至于实际输出函数指针的地址,发生的事情取决于目标平台的C库和编译器的供应商。
答案 2 :(得分:2)
将函数指针转换为整数,然后再将其强制转换为指针以使用“%p”。
#include <stdio.h>
int main() {
int (*funcptr)() = main;
printf("%p\n", (void *)(size_t) funcptr);
printf("%p\n", (void *)(size_t) main);
return 0;
}
请注意,在某些平台上(例如“中型”或“紧凑型”内存模型中的16位DOS),指向数据的指针和指向函数的指针的大小不同。
答案 3 :(得分:1)
使用gcc 4.3.4,使用开关-O2 -Wstrict-aliasing,dreamlax的答案将产生:
warning: dereferencing type-punned pointer will break strict-aliasing rules
已添加:我认为对于有关 endianness 和大小的回答的反对是合理的,他的解决方案没有解决(没有双关语意图) )。达斯汀关于使用联合演员的建议可能是合法的(虽然从我读到的内容中似乎存在一些争议,但你的编译器确实比法律重要)。但他的代码可以通过单行简化(或根据您的品味进行混淆):
printf("%p\n", ((union {int (*from)(void); void *to;})funcptr).to);
这会删除gcc严格别名警告(但它是'正确'?)。
如果您使用-pedantic开关,或者正在使用例如,聚合强制转换将无法正常工作SGI IRIX,所以你需要使用:
printf("%p\n", ((union {int (*from)(void); void *to;} *)&funcptr)->to);
但是对于最初的问题:它的起源在于使用-pedantic,我认为这有点迂腐:)。
进一步修改:请注意,您不能在最后一个示例中使用 main ,如:
printf("%p\n", ((union {int (*from)(void); void *to;}) main).to); // ok
printf("%p\n", ((union {int (*from)(void); void *to;} *)&main)->to); // wrong!
因为当然&amp; main 衰退到主要。
答案 4 :(得分:1)
试试这个:
#include <stdio.h>
#include <inttypes.h>
int main() {
int (*funcptr)() = main;
unsigned char *p = (unsigned char *)&funcptr;
int i;
/* sample output: 00000000004005e0 */
printf("%016"PRIxPTR"\n", (uintptr_t)main);
/* sample output: 00000000004005e0 */
printf("%016"PRIxPTR"\n", (uintptr_t)funcptr);
/* reflects the fact that this program is running on little-endian machine
sample output: e0 05 40 00 00 00 00 00 */
for (i = 0; i < sizeof funcptr; i++)
{
printf("%02x ", p[i]);
}
putchar('\n');
return 0;
}
使用了这个标志:
gcc -ansi -pedantic -Wall -O2 -Wstrict-aliasing c.c
使用这些标志没有发出警告
答案 5 :(得分:0)
我不确定这是否是犹太教,但是它实现了效果,没有循环,联合,强制转换为非指针类型,或除string.h
之外的额外依赖
int (*funcptr)() = main;
void* p = NULL;
memcpy(&p, (void**) &funcptr, sizeof(funcptr));
printf("%p", p);
GCC 7.1.1上没有gcc -ansi -pedantic -Wall -Wstrict-aliasing
的警告