jpa*_*jpa 3 c function-pointers pointer-arithmetic language-lawyer c11
通过评论我的回答启发这里.
这一系列步骤在C标准(C11)中是否合法?
void*void*或者相当于代码:
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似乎没有涵盖这一点:指针.
你的代码是正确的.
指向函数的指针是一个对象,并且您正在将一个指向对象(指向函数指针的指针)的指针转换为void指针并再次返回; 然后最终取消引用指向对象的指针.
至于char指针算术,这由C11 的脚注106引用:
106)接近指针运算的另一种方法是首先将指针转换为字符指针:在此方案中,首先将转换后的指针中添加或减去的整数表达式乘以最初指向的对象的大小. ,并将结果指针转换回原始类型.对于指针减法,字符指针之间差异的结果类似地除以最初指向的对象的大小.当以这种方式查看时,实现仅需要在对象结束之后提供一个额外字节(其可以与程序中的另一个对象重叠)以满足"超过最后一个元素"的要求.
是的,代码没问题。这里有各种陷阱和转换规则:
void*是指向对象类型的指针的通用指针类型。任何指向对象类型的指针都可以void*隐式转换为/从。(C17 6.3.2.3 §1)。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*.
此外,关于指针算法:
void*。(C17 6.3.2.2) 这种算术是一种常见的非标准扩展,应该避免。相反,使用指向字符类型的指针。所以,(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)