是否有任何方法可以打印指向ansi c c中函数的指针?当然,这意味着您必须将函数指针强制转换为void指针,但这似乎是不可能的??

#include <stdio.h>

int main() {
    int (*funcptr)() = main;

    printf("%p\n", (void* )funcptr);
    printf("%p\n", (void* )main);

    return 0;
}

$GCC-ANSI-书呆子-墙壁测试.c-o 测试
测试C:功能正常 “主要”:
测试C:6:警告:ISO C 禁止转换函数指针 到对象指针类型
测试:C:7: 警告:ISO C禁止转换 指向对象指针的函数指针 类型
$/测试
0x400 518
0x400 518

这是“有效的”,但不是标准的……

6 回复  |  直到 7 年前
    1
  •  41
  •   Community CDub    8 年前

    唯一合法的方法是使用字符类型访问组成指针的字节。这样地:

    #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 ,是未定义的行为。

    组成函数指针的字节实际上是什么 意思是 是否依赖于实现。例如,它们可以将索引表示为一个函数表。

        2
  •  5
  •   Dustin    15 年前

    使用联合可以绕过警告/错误,但结果仍然(很可能)是未定义的行为:

    #include <stdio.h>
    
    int
    main (void)
    {
      union
      {
        int (*funcptr) (void);
        void *objptr;
      } u;
      u.funcptr = main;
    
      printf ("%p\n", u.objptr);
    
      return 0;
    }
    

    您可以比较两个函数指针(例如 printf ("%i\n", (main == funcptr)); )使用if语句来测试它们是否相等(我知道这完全破坏了目的,可能非常不相关),但就实际输出函数指针的地址而言,所发生的事情取决于目标平台的C库和编译器的供应商。

        3
  •  2
  •   dan04    15 年前

    将函数指针强制转换为整数,然后再次强制转换为指针以使用“%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),指向数据的指针和指向函数的指针的大小不相同。

        4
  •  1
  •   Michael Buen    15 年前

    试试这个:

    #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
  •  1
  •   Joseph Quinsey Taseen    15 年前

    使用GCC4.3.4,使用开关-O2-Wstrict别名,Dreamlax的答案将产生:

    warning: dereferencing type-punned pointer will break strict-aliasing rules
    

    补充: 我认为反对CAF的回答 迂回性 大小是合理的,他的解决方案没有解决(没有双关语的意图)。达斯汀使用工会演员阵容的建议可能是合法的(尽管从我读到的内容来看,似乎有一些争论,但是 你的 编译器确实比法律重要。但是他的代码可以通过一行代码简化(或模糊化,这取决于您的口味):

    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);
    

    但是关于这个原始问题:它的起源在于-学究式的使用,我认为这有点学究式的。

    进一步编辑: 注意您不能使用 主要的 在上一个示例中,如:

    printf("%p\n", ((union {int (*from)(void); void *to;})   main).to);  // ok
    printf("%p\n", ((union {int (*from)(void); void *to;} *)&main)->to); // wrong!
    

    当然是因为 &主要的 衰变到 主要的 .

        6
  •  0
  •   Jon Deaton    7 年前

    我不确定这是否是Kosher,但是它在没有循环、联合、强制转换为非指针类型或其他依赖项的情况下实现了效果。 string.h

    int (*funcptr)() = main;
    void* p = NULL;
    memcpy(&p, (void**) &funcptr, sizeof(funcptr));
    printf("%p", p);
    

    没有警告 gcc -ansi -pedantic -Wall -Wstrict-aliasing 关于GCC 7.1.1