你可以将"指向函数指针的指针"转换为void*

jpa*_*jpa 3 c function-pointers pointer-arithmetic language-lawyer c11

通过评论我的回答启发这里.

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

  1. 创建一个函数指针数组
  2. 一个指针指向的第一项和铸造的指针函数指针void*
  3. 对此执行指针运算 void*
  4. 将其强制转换为指向函数指针的指针并取消引用它.

或者相当于代码:

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
Run Code Online (Sandbox Code Playgroud)

我认为这是允许的,因为实际的函数指针只能通过正确键入的指针访问.但Andrew Henle指出,标准部分6.3.2.3似乎没有涵盖这一点:指针.

Ant*_*ala 8

你的代码是正确的.

指向函数的指针是一个对象,并且您正在将一个指向对象(指向函数指针的指针)的指针转换为void指针并再次返回; 然后最终取消引用指向对象的指针.

至于char指针算术,这由C11 的脚注106引用:

106)接近指针运算的另一种方法是首先将指针转换为字符指针:在此方案中,首先将转换后的指针中添加或减去的整数表达式乘以最初指向的对象的大小. ,并将结果指针转换回原始类型.对于指针减法,字符指针之间差异的结果类似地除以最初指向的对象的大小.当以这种方式查看时,实现仅需要在对象结束之后提供一个额外字节(其可以与程序中的另一个对象重叠)以满足"超过最后一个元素"的要求.

  • 指针算法也是正确的,因为它使用强制转换为`char`和`char`免于有效类型规则. (2认同)

Lun*_*din 5

是的,代码没问题。这里有各种陷阱和转换规则:

  • C 将所有类型分为两大类:对象和函数。指向函数的指针是标量类型,而标量类型又是一个对象。(C17 6.2.5)
  • void*是指向对象类型的指针的通用指针类型。任何指向对象类型的指针都可以void*隐式转换为/从。(C17 6.3.2.3 §1)。
  • 对于指向函数类型的指针,不存在这种通用指针类型。因此,函数指针不能转换为 a void*,反之亦然。(C17 6.3.2.3 §1)
  • 但是,任何函数指针类型都可以转换为另一种函数指针类型并返回,这允许我们使用诸如void(*)(void)泛型函数指针类型之类的东西。只要你不通过错误的函数指针类型调用函数,就可以了。(C17 6.3.2.3 §8)

函数指针指向函数,但它们本身就是对象,就像任何指针一样。因此,您可以使用 avoid*指向函数指针的地址

因此,使用 avoid*指向函数指针是可以的。但不使用它直接指向一个函数。如果void *ptr1 = array;数组衰减为指向第一个元素的指针, a void (**)(void)(相当于voidfunc*您的示例)。您可以使用void*.

此外,关于指针算法:

  • 不能对 a 执行指针运算void*。(C17 6.3.2.2) 这种算术是一种常见的非标准扩展,应该避免。相反,使用指向字符类型的指针。
  • 作为特殊情况,指向字符类型的指针可用于迭代任何对象(C17 6.2.3.3 §7)。除了对对齐的担忧之外,如果您取消引用字符指针(C17 6.5 §7),这样做是明确定义的并且不会违反“严格指针别名”。

所以,(char*)ptr1 + sizeof(voidfunc);也还好。然后从 转换void*voidfunc*,转换voidfunc为数组中存储的原始函数指针类型。

正如评论中所指出的,您可以通过typedef对函数类型使用 a来显着提高此代码的可读性:

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
Run Code Online (Sandbox Code Playgroud)