【问题标题】:how to understand using typedef to define a function pointer?如何理解使用 typedef 定义函数指针?
【发布时间】:2021-09-03 15:12:53
【问题描述】:

我认为通常 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后面是三个字,编译器怎么解析这个语句呢?

谢谢!

【问题讨论】:

  • This may help you out 并提供(我认为)更具可读性的 C++ 解决方案。
  • 我一直保持头脑清醒的方式是这样想:在typedef, 中,编译器查看整个表达式并挑选出它唯一没有的以前听说过。并假设这就是您正在键入的内容。所以INT 在第一个表达式中,GL_GENBUFFERS 在第二个表达式中。我怀疑这在技术上是否正确,但它可以帮助我保持正确。
  • 它仍然需要出现在那个位置,在void之后,编译器才能意识到它是一个函数指针而不是别的东西
  • 在 C++11 及更高版本中,更喜欢using,它是更强大和更干净的typedef,例如:using INT = int; using GL_GENBUFFERS = void (*)(GLsizei, GLuint*);

标签: c++ c function-pointers declaration typedef


【解决方案1】:

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

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

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

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

void foo( int, double );

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

用简单的英语来说,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 与存储类说明符(staticautoregister)分组,但它的行为与其他存储类说明符不同 - 不会影响存储或可见性在声明的事物中,它使声明符中的标识符成为类型的别名。如果我们在上述声明的前面加上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 参数并返回void 的函数的指针”的别名(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 或类似的东西打印它的值)。

【讨论】:

    【解决方案2】:

    如果你有该类型的函数

    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*);
    

    【讨论】:

      【解决方案3】:

      让我们考虑下面的代码

      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 的类型,顾名思义,是SomeClass 类的pointer to member function,接受int 类型的参数,并返回void

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-06-27
        • 2014-07-26
        • 2011-05-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-08
        相关资源
        最近更新 更多