如何理解使用 typedef 定义函数指针?

how to understand using typedef to define a function pointer?

我认为通常 typedef 可以这样使用:

typedef int INT

第一个词是C/C++中的某个关键字,第二个词是第一个词的别名。

但是最近我注意到了这个说法

typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);
GL_GENBUFFERS glGenBuffers  = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
GLuint buffer;
glGenBuffers(1, &buffer);

typedef后面好像是三个字,编译器怎么解析这个语句?

谢谢!

如果你有

类型的函数
void (GLsizei, GLuint*);

那么指向函数类型的指针将类似于

void (*GL_GENBUFFERS) (GLsizei, GLuint*);

如果添加 typedef 说明符,例如

typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);

那么在这种情况下 GL_GENBUFFERS 不是指针类型的对象而是指针类型的别名 void (*) (GLsizei, GLuint*).

另一种方法是首先为函数类型引入别名,例如

typedef void GL_GENBUFFERS(GLsizei, GLuint*);

那么指向类型void (GLsizei, GLuint*)的函数的指针类型看起来像GL_GENBUFFERS *

在 C++ 中,您可以使用类似

的别名声明
using GL_GENBUFFERS = void ( * )(GLsizei, GLuint*);

让我们考虑以下代码

typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);

int main()
{
   static_assert(std::is_same<GL_GENBUFFERS, void(*)(GLsizei, GLuint*)>::value,"Not same")
}

如果你试试,你可以看到上面的代码,你不会看到消息Not same,这意味着这两个具有相同的类型。

你也可以这样做

typedef void(SomeClass::*member_func_ptr)(int, int);

member_func_ptr的类型,顾名思义,就是classSomeClass的一个,接受int类型的参数,返回void.

让我们从一般性的声明语法开始(我将使用 C 术语,尽管 C++ 大体相似)。在 C 和 C++ 中,声明包含一个或多个 声明说明符 的序列,后跟零个或多个 声明符 的逗号分隔列表。

声明说明符包括类型说明符(intdoublecharunsigned等)、类型限定符(constvolatile,等等),存储 class 说明符(staticregistertypedef,等等),structunion 说明符,以及其他一些我们不会在这里讨论的内容。

声明符包括被声明事物的名称,以及关于该事物的指针性、数组性或函数性(在 C++ 中您也有引用性)的信息。

当你声明一个函数时,比如

void foo( int, double );

void是声明说明符(type specifier),foo( int, double )是声明符。 foo的类型完全由声明说明符和声明符的组合指定:

     foo                     -- foo
     foo(             )      -- is a function taking
     foo(             )      --   unnamed parameter
     foo( int         )      --   is an int
     foo( int,        )      --   unnamed parameter
     foo( int, double )      --   is a double
void foo( int, double )      -- returning void

用简单的英语来说,foo 的类型是“接受 intdouble 参数并返回 void 的函数。”

您也可以声明指向函数的指针:

       fptr                  -- fptr
     (*fptr)                 -- is a pointer to
     (*fptr)(             )  --   function taking
     (*fptr)(             )  --     unnamed parameter
     (*fptr)( int         )  --     is an int
     (*fptr)( int,        )  --     unnamed parameter
     (*fptr)( int, double )  --     is a double
void (*fptr)( int, double )  --   returning void

同样,唯一的声明说明符是 void,声明符是 (*fptr)( int, double )

出于语法目的,typedef 与存储 class 说明符(staticautoregister)分组,但它不表现得像其他存储 class 说明符 - 它不会影响正在声明的事物的存储或可见性,而是使声明符中的标识符成为该类型的 别名 。如果我们在上面声明的前面加上typedef

typedef void (*fptr)( int, double );

然后它读作

               fptr                   -- fptr
typedef        fptr                   -- IS AN ALIAS FOR THE TYPE
typedef      (*fptr)                  --   pointer to
typedef      (*fptr)(             )   --     function taking
typedef      (*fptr)(             )   --       unnamed parameter
typedef      (*fptr)( int         )   --       is an int
typedef      (*fptr)( int,        )   --       unnamed parameter
typedef      (*fptr)( int, double )   --       is a double
typedef void (*fptr)( int, double )   --     returning void

IOW,fptr 是类型“指向采用 intdouble 参数并返回 [=34= 的函数的指针”的别名(typedef 名称) ]",你可以用它来声明该类型的指针对象:

fptr fp1, fp2;

你可以用其他指针类型做同样的事情1:

typedef int *intp;         // intp is an alias for the type "pointer to int";
typedef double (*arr)[10]; // arr is an alias for the type "pointer to 10-element array of double"

声明符可能会变得非常复杂。您可以拥有指向函数的指针:

T (*ptr)();

指向数组的指针:

T (*ptr)[N];

函数指针数组:

T (*ptr[N])();

返回数组指针的函数:

T (*foo())[N];

指向返回数组指针的函数的指针数组:

T (*(*arr[N])())[M];

等等等等,把 typedef 贴在他们中的任何一个前面都可以:

typedef T (*(*arr[N])())[M];

表示 arr 是类型“指向函数的指针的 N​​ 元素数组返回指向 T 的 M 元素数组的指针”类型的别名。


  1. 通常,您不想在 typedef 后面隐藏指向标量类型的指针,除非您可以保证使用该类型的程序员永远不必知道该类型的底层指针性(即,将永远不必用 * 明确取消引用它或尝试用 %p 或类似的东西打印它的值)。