代码之家  ›  专栏  ›  技术社区  ›  jpa

你能将“指向函数指针的指针”转换为void吗*

  •  3
  • jpa  · 技术社区  · 6 年前

    灵感来自对我答案的评论 here .

    这一系列步骤在C标准(C11)中是否合法?

    1. 将指针指向第一个条目并将其强制转换为 指向函数指针的指针 void*
    2. 无效*
    3. 指向函数指针的指针 并取消引用。

    void foo(void) { ... }
    void bar(void) { ... }
    
    typedef void (*voidfunc)(void);
    voidfunc array[] = {foo, bar}; // Step 1
    
    void *ptr1 = array; // Step 2
    
    void *ptr2 = (char*)ptr1 + sizeof(voidfunc); // Step 3
    
    voidfunc bar_ptr = *(voidfunc*)ptr2; // Step 4
    

    我认为这是允许的,因为实际的函数指针只能通过正确类型的指针访问。但安德鲁亨勒指出,这似乎不包括在 Standard section 6.3.2.3: Pointers .

    3 回复  |  直到 6 年前
        1
  •  5
  •   Lundin    6 年前

    是的,密码很好。这里有各种各样的陷阱和转换规则:

    • C将所有类型分为两大类:对象和函数。指向函数的指针是 标量类型 这又是一个物体(C17(第6.2.5节)
    • void* 是指向对象类型的指针的泛型指针类型。任何指向对象类型的指针都可以转换为
    • 无效* 反之亦然(C17(第6.3.2.3条第1款)
    • void(*)(void) 作为泛型函数指针类型。只要不通过错误的函数指针类型调用函数,就可以了(C17(第6.3.2.3条第8款)

    无效* 指向 函数指针的地址 .

    无效* void *ptr1 = array; 数组将衰减为指向第一个元素的指针 void (**)(void) voidfunc* 在你的例子中)。您可以用 无效*

    此外,关于指针算法:

    • 无效* . (C17 6.3.2.2)这种算法是一种常见的非标准扩展,应该避免。相反,使用指向字符类型的指针。
    • 作为特例,指向字符类型的指针可用于迭代任何对象(C17 6.2.3.3§7)。除了有关对齐的问题外,如果取消引用字符指针(C17 6.5§7),那么这样做是有明确定义的,并且不违反“严格的指针别名”。

    因此, (char*)ptr1 + sizeof(voidfunc); 虚空函数* voidfunc

    正如注释中所指出的,通过使用 typedef 对于函数类型:

    typedef void (voidfunc)(void);
    
    voidfunc* array[] = {&foo, &bar}; // Step 1
    void* ptr1 = array; // Step 2
    void* ptr2 = (char*)ptr1 + sizeof(voidfunc*); // Step 3
    voidfunc* bar_ptr = *(voidfunc**)ptr2; // Step 4
    
        2
  •  8
  •   Antti Haapala -- Слава Україні    6 年前

    你的代码是正确的。

    指向函数的指针是一个对象,您正在将指针强制转换为 (指向函数指针的指针)指向 void 指针来回移动;最后取消对对象的指针的引用。

    至于 char 指针算法,这是指 footnote 106 C11类型:

    106)实现指针算法的另一种方法是首先将指针转换为字符指针:在这种方案中,向转换后的指针加上或减去的整数表达式首先乘以原来指向的对象的大小,得到的指针转换回原来的类型。对于指针减法,字符指针之间的差的结果同样除以最初指向的对象的大小。以这种方式来看,一个实现只需在对象结束后提供一个额外字节(可能与程序中的另一个对象重叠),即可满足“超过最后一个元素一个”的要求。

        3
  •  0
  •   n. m. could be an AI    6 年前

    指针算术打开 void* 不是C语言的。你不是在做,而是在做指针运算 char* 字符* 无效*

    将指针强制转换为函数指针 是没有根据的,因为指向任何对象类型的指针都可以强制转换为 无效* .

    然而,C标准似乎不允许使用 (T*)((char*)p + sizeof(T)) 代替 (p+1) p 是指向类型为的数组的元素的指针 T