【问题标题】:Typedef function pointer?typedef函数指针?
【发布时间】:2011-05-16 18:38:31
【问题描述】:

我正在学习如何动态加载 DLL,但我不明白的是这一行

typedef void (*FunctionFunc)();

我有几个问题。如果有人能够回答他们,我将不胜感激。

  1. 为什么使用typedef
  2. 语法看起来很奇怪;在void 之后不应该有函数名什么的吗?它看起来像一个匿名函数。
  3. 是否创建了函数指针来存储函数的内存地址?

所以我现在很困惑;你能帮我澄清一下吗?

【问题讨论】:

  • 看看链接(最后一节)learncpp.com/cpp-tutorial/78-function-pointers
  • 需要注意的是c++11以后可以用using FunctionFunc = void (*)();代替。更清楚一点,您只是在声明一个类型的名称(指向函数的指针)
  • 只是添加到@user362515,对我来说更清晰的形式是:using FunctionFunc = void(void);
  • @topspin IIRC 这两个不一样。一种是函数指针类型,另一种是函数类型。存在隐式转换,这就是它起作用的原因,IANA(C++)L 所以,可以介入并纠正我。无论如何,如果打算定义一个指针类型,我认为* 的语法更明确。
  • 这里是a related question I asked a long time ago 说明为什么myFuncPtr()(*myFuncPtr)() 都是有效的函数调用。

标签: c++ c pointers typedef


【解决方案1】:

typedef 是一种将名称与类型相关联的语言结构。
例如,您可以像使用原始类型一样使用它

typedef int myinteger;
typedef char *mystring;
typedef void (*myfunc)();

像使用它们

myinteger i;   // is equivalent to    int i;
mystring s;    // is the same as      char *s;
myfunc f;      // compile equally as  void (*f)();

如您所见,您可以将 typedefed 名称替换为上面给出的定义。

难点在于C和C++中指向函数语法和可读性的指针,typedef可以提高此类声明的可读性。但是,语法是合适的,因为函数 - 与其他更简单的类型不同 - 可能有返回值和参数,因此有时需要冗长而复杂的函数指针声明。

对于指向函数数组的指针以及其他一些更间接的风格,可读性可能开始变得非常棘手。

回答你的三个问题

  • 为什么要使用 typedef? 为了便于阅读代码 - 特别是对于指向函数或结构名称的指针。

  • 语法看起来很奇怪(在函数声明的指针中) 这种语法读起来并不明显,至少在开始时是这样。使用typedef 声明反而更容易阅读

  • 是否创建了函数指针来存储函数的内存地址? 是的,函数指针存储函数的地址。这与 typedef 构造无关,它只会简化程序的写入/读取;编译器只是在编译实际代码之前扩展 typedef 定义。

例子:

typedef int (*t_somefunc)(int,int);

int product(int u, int v) {
  return u*v;
}

t_somefunc afunc = &product;
...
int x2 = (*afunc)(123, 456); // call product() to calculate 123*456

【讨论】:

  • 在最后一个例子中,'square'不仅仅指同一个东西,即指向函数的指针而不是使用&square。
  • 问题,在您的第一个 typedef 示例中,您的格式为 typedef type alias,但函数指针似乎只有 2 个参数,typedef type。别名是否默认为类型参数中指定的名称?
  • @pranavk:是的,square&square(实际上,*square**square)都指向同一个函数指针。
  • @user814628:不清楚你在问什么。使用typedef int newname,您将newname 变成int 的别名。使用typedef int (*func)(int),您将func 设为int (*)(int) 的别名——一个指向函数的指针,该函数接受int 参数并返回int 值。
  • 我想我只是对订购感到困惑。使用 typedef int (*func)(int),我知道 func 是一个别名,只是有点困惑,因为别名与类型纠缠在一起。以typedef int INT 为例,如果typedef 函数指针的形式为typedef int(*function)(int) FUNC_1,我会更容易。这样我就可以在两个单独的标记中看到类型和别名,而不是被网格化为一个。
【解决方案2】:
  1. typedef 用于别名类型;在这种情况下,您将 FunctionFunc 别名为 void(*)()

  2. 确实语法看起来很奇怪,看看这个:

    typedef   void      (*FunctionFunc)  ( );
    //         ^                ^         ^
    //     return type      type name  arguments
    
  3. 不,这只是告诉编译器FunctionFunc 类型将是一个函数指针,它没有定义一个,像这样:

    FunctionFunc x;
    void doSomething() { printf("Hello there\n"); }
    x = &doSomething;
    
    x(); //prints "Hello there"
    

【讨论】:

  • typedef not 声明了一个新类型。您可以有许多 typedef 定义的相同类型的名称,并且它们不同(例如,函数重载)。在某些情况下,关于如何使用名称,typedef 定义的名称不完全等同于它的定义,但多个 typedef 定义的名称相同。
【解决方案3】:

如果没有 typedef 字,在 C++ 中,声明将声明一个变量 FunctionFunc,其类型为指向无参数函数的指针,返回 void

使用typedef,它将FunctionFunc 定义为该类型的名称。

【讨论】:

    【解决方案4】:

    如果您可以使用 C++11,您可能需要使用 std::functionusing 关键字。

    using FunctionFunc = std::function<void(int arg1, std::string arg2)>;
    

    【讨论】:

    • 没有 C++11 using 关键字就像 typedef std::function&lt;void(int, std::string)&gt; FunctionFunc;,以防万一有人想要另一个没有 C++11 的函数的包装器
    【解决方案5】:
    #include <stdio.h>
    #include <math.h>
    
    /*
    To define a new type name with typedef, follow these steps:
    1. Write the statement as if a variable of the desired type were being declared.
    2. Where the name of the declared variable would normally appear, substitute the new type name.
    3. In front of everything, place the keyword typedef.
    */
    
    // typedef a primitive data type
    typedef double distance;
    
    // typedef struct 
    typedef struct{
        int x;
        int y;
    } point;
    
    //typedef an array 
    typedef point points[100]; 
    
    points ps = {0}; // ps is an array of 100 point 
    
    // typedef a function
    typedef distance (*distanceFun_p)(point,point) ; // TYPE_DEF distanceFun_p TO BE int (*distanceFun_p)(point,point)
    
    // prototype a function     
    distance findDistance(point, point);
    
    int main(int argc, char const *argv[])
    {
        // delcare a function pointer 
        distanceFun_p func_p;
    
        // initialize the function pointer with a function address
        func_p = findDistance;
    
        // initialize two point variables 
        point p1 = {0,0} , p2 = {1,1};
    
        // call the function through the pointer
        distance d = func_p(p1,p2);
    
        printf("the distance is %f\n", d );
    
        return 0;
    }
    
    distance findDistance(point p1, point p2)
    {
    distance xdiff =  p1.x - p2.x;
    distance ydiff =  p1.y - p2.y;
    
    return sqrt( (xdiff * xdiff) + (ydiff * ydiff) );
    }
    

    【讨论】:

    • 什么情况下需要'&'?例如,'func_p = &findDistance' 和 'func_p = findDistance' 是否同样有效?
    • 函数名是一个指针,所以你不需要和它一起使用'&'。换句话说,当考虑函数指针时,'&' 是可选的。但是,对于原始数据类型,您需要使用“&”来获取其地址。
    • 奇怪的是,'&' 可以是可选的。如果 typedef 用于创建指向原语的指针(即typedef (*double) p,'&' 是可选的吗?
    • 我想你想输入typedef double* p 来定义一个双精度指针。如果要从原始变量填充p 指针,则需要使用“&”。附带说明,我们使用 * 来取消引用指针。在函数指针中使用* 来取消引用指针(函数名)并转到函数指令所在的内存块。
    【解决方案6】:

    对于语法的一般情况,您可以查看annex A of the ANSI C standard

    在 Backus-Naur 表单中,您可以看到 typedef 的类型为 storage-class-specifier

    declaration-specifiers这个类型中可以看到可以混用很多说明符类型,顺序无关紧要。

    例如,正确的说法是,

    long typedef long a;
    

    将类型a 定义为long long 的别名。因此,要了解详尽使用的 typedef,您需要查阅一些定义语法的 backus-naur 形式(ANSI C 有许多正确的语法,而不仅仅是 ISO 的语法)。

    当您使用 typedef 为函数类型定义别名时,您需要将别名放在放置函数标识符的相同位置。在您的情况下,您将类型 FunctionFunc 定义为指向函数的指针的别名,该函数的类型检查在调用时被禁用并且不返回任何内容。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多