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

zjn*_*yly 2 c c++ typedef function-pointers declaration

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

typedef int INT
Run Code Online (Sandbox Code Playgroud)

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

但最近我注意到这个说法

typedef void (*GL_GENBUFFERS) (GLsizei, GLuint*);
GL_GENBUFFERS glGenBuffers  = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
GLuint buffer;
glGenBuffers(1, &buffer);
Run Code Online (Sandbox Code Playgroud)

看起来typedef后面有三个单词,那么编译器如何解析这个语句呢?

谢谢!

Joh*_*ode 5

让我们首先讨论一般的声明语法(我将使用 C 术语,尽管 C++ 非常相似)。在 C 和 C++ 中,声明包含一系列一个或多个声明说明符,后跟零个或多个声明符的逗号分隔列表。

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

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

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

void foo( int, double );
Run Code Online (Sandbox Code Playgroud)

void是声明说明符(类型说明符),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
Run Code Online (Sandbox Code Playgroud)

用简单的英语来说, 的类型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
Run Code Online (Sandbox Code Playgroud)

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

出于语法目的,与存储类说明符 ( 、、 )typedef分组,但它的行为与其他存储类说明符不同 - 它不会影响所声明事物的存储或可见性,而是使声明符中的标识符成为别名 对于类型。如果我们坚持上面声明的前面:staticautoregistertypedef

typedef void (*fptr)( int, double );
Run Code Online (Sandbox Code Playgroud)

那么它读作

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

IOW是“指向带有和参数并返回的函数的指针”类型的fptr别名(名称) ,您可以使用它来声明该类型的指针对象:typedefintdoublevoid

fptr fp1, fp2;
Run Code Online (Sandbox Code Playgroud)

您可以对其他指针类型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"
Run Code Online (Sandbox Code Playgroud)

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

T (*ptr)();
Run Code Online (Sandbox Code Playgroud)

指向数组的指针:

T (*ptr)[N];
Run Code Online (Sandbox Code Playgroud)

函数指针数组:

T (*ptr[N])();
Run Code Online (Sandbox Code Playgroud)

返回数组指针的函数:

T (*foo())[N];
Run Code Online (Sandbox Code Playgroud)

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

T (*(*arr[N])())[M];
Run Code Online (Sandbox Code Playgroud)

等等,坚持typedef在其中任何一个前面都会起作用:

typedef T (*(*arr[N])())[M];
Run Code Online (Sandbox Code Playgroud)

meansarr是“N 元素指针数组,该函数返回 M 元素数组的指针T”类型的别名。


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