您可以将“指向功能指针的指针"转换为吗?无效* [英] Can you cast a "pointer to a function pointer" to void*

查看:117
本文介绍了您可以将“指向功能指针的指针"转换为吗?无效*的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

受评论的启发此处.

此步骤序列在C标准(C11)中合法吗?

  1. 制作一个函数指针数组
  2. 获取指向第一个条目的指针,并将该 pointer指针转换为函数指针void*
  3. 对该void*
  4. 执行指针算术运算
  5. 将其放回函数指针的指针并取消引用.
  1. Make an array of function pointers
  2. Take a pointer to the first entry and cast that pointer to function pointer to void*
  3. Perform pointer arithmetic on that void*
  4. Cast it back to pointer to function pointer and dereference it.

或等效地作为代码:

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

我认为这是允许的,因为实际的函数指针只能通过正确键入的指针来访问.但是Andrew Henle指出,标准第6.3.2.3节:指针.

I thought that this would be allowed, as the actual function pointers are only accessed through properly typed pointer. But Andrew Henle pointed out that this doesn't seem to be covered by Standard section 6.3.2.3: Pointers.

推荐答案

是的,代码很好.这里有各种陷阱和转换规则:

Yes, the code is fine. There's various pitfalls and conversion rules at play here:

  • C将所有类型分为两个主要类别:对象和函数.指向函数的指针是标量类型,而该对象又是对象. (C17 6.2.5)
  • void*是指向对象类型的指针的通用指针类型.任何指向对象类型的指针都可以隐式地与void*进行相互转换. (C17 6.3.2.3§1).
  • 对于函数类型的指针,不存在此类通用指针类型.因此,函数指针不能转换为void*,反之亦然. (C17 6.3.2.3§1)
  • 但是,任何函数指针类型都可以转换为另一种函数指针类型,然后再转换回去,从而使我们可以将void(*)(void)之类的东西用作通用函数指针类型.只要您不通过错误的函数指针类型调用函数,就可以了. (C17 6.3.2.3§8)
  • C splits all types in two main categories: objects and functions. A pointer to a function is a scalar type which in turn is an object. (C17 6.2.5)
  • void* is the generic pointer type for pointers to object type. Any pointer to object type may be converted to/from void*, implicitly. (C17 6.3.2.3 §1).
  • No such generic pointer type exists for pointers to function type. Thus a function pointer cannot be converted to a void* or vice versa. (C17 6.3.2.3 §1)
  • However, any function pointer type can be converted to another function pointer type and back, allowing us to use something like for example void(*)(void) as a generic function pointer type. As long as you don't call the function through the wrong function pointer type, it is fine. (C17 6.3.2.3 §8)

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

Function pointers point to functions, but they are objects in themselves, just like any pointer is. And so you can use a void* to point at the address of a function pointer.

因此,使用void*指向函数指针就可以了.但是不能用它直接指向一个函数.在void *ptr1 = array;的情况下,数组衰减为指向第一个元素void (**)(void)的指针(在您的示例中等同于voidfunc*).您可以使用void*指向此类函数指针.

Therefore, using a void* to point at a function pointer is fine. But not using it to point directly at a function. In case of void *ptr1 = array; the array decays into a pointer to the first element, a void (**)(void) (equivalent to voidfunc* in your example). You may point at such a pointer to function-pointer with a void*.

此外,关于指针算法:

  • 不能在void*上执行指针算术运算. (C17 6.3.2.2)这种算术运算是常见的非标准扩展,应避免.而是使用指向字符类型的指针.
  • 在特殊情况下,可以使用指向字符类型的指针来迭代任何对象(C17 6.2.3.3§7).除了对对齐的关注之外,如果您取消引用字符指针(C17 6.5§7),这样做的定义是明确的,并且不会违反严格的指针别名".
  • No pointer arithmetic can be performed on a void*. (C17 6.3.2.2) Such arithmetic is a common non-standard extension that should be avoided. Instead, use a pointer to character type.
  • A pointer to character type may, as a special case, be used to iterate over any object (C17 6.2.3.3 §7). Apart from concerns regarding alignment, doing so is well-defined and does not violate "strict pointer aliasing", should you de-reference the character pointer (C17 6.5 §7).

因此,(char*)ptr1 + sizeof(voidfunc);也可以.然后,从void*转换为voidfunc*,再转换为voidfunc,这是存储在数组中的原始函数指针类型.

Therefore, (char*)ptr1 + sizeof(voidfunc); is also fine. You then convert from void* to voidfunc*, to voidfunc which is the original function pointer type stored in the array.

如注释中所述,可以通过对函数类型使用typedef来显着提高此代码的可读性:

As been noted in comments, you can improve readability of this code significantly by using a typedef to a function type:

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

这篇关于您可以将“指向功能指针的指针"转换为吗?无效*的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆