Typedef函数指针?


458

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

typedef void (*FunctionFunc)();

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

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

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


5
看一下链接(最后一部分)learncpp.com/cpp-tutorial/78-function-pointers
狂热爱好者

9
应该注意的是,由于using FunctionFunc = void (*)();可以使用c ++ 11 代替。更加清楚的是,您只是在声明类型的名称(指向函数的指针)
user362515 '16

只是添加到@ user362515,对我来说更清晰的形式是:using FunctionFunc = void(void);
topspin

@topspin IIRC这两个不相同。一种是函数指针类型,另一种是函数类型。有一个隐式转换,这就是它起作用的原因,IANA(C ++)L因此,一个人可以介入并纠正我。无论如何,如果打算定义一个指针类型,我认为带有的语法会*更明确。
user362515 '16

Answers:


463

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

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

难点在于在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

6
在最后一个示例中,不仅“正方形”是指同一事物,即指向函数的指针,而不是使用&square。
pranavk

2
问题,在您的第一个typedef示例中,您具有以下形式:typedef type alias函数指针似乎只有2个参数typedef type。别名是否默认为类型实参中指定的名称?
dchhetri

2
@pranavk:是的,square并且和&square(实际上,*square**square)都引用相同的函数指针。
乔纳森·莱夫勒

6
@ user814628:不清楚您要问什么。使用typedef int newname,您将成为newname的别名int。使用typedef int (*func)(int),您将成为func别名int (*)(int)—指向接受int参数并返回int值的函数的指针。
乔纳森·勒夫勒

10
我想我只是对订购感到困惑。使用typedef int (*func)(int),我知道func是别名,只是有点困惑,因为别名与类型纠缠在一起。通过转至typedef int INT作为一个例子,我会更易于如果typedef的函数指针是形式的typedef int(*function)(int) FUNC_1。这样,我可以在两个单独的令牌中看到类型和别名,而不是被划分为一个。
dchhetri

188
  1. typedef用于别名类型;在这种情况下,您将别名FunctionFuncvoid(*)()

  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"

27
typedef没有宣布新的类型。您可以具有许多typedef相同类型的-定义名称,并且它们之间没有区别(例如,函数重载)。在某些情况下,就如何使用该名称而言,typedef-defined名称并不完全等同于其typedef定义的名称,而是相同的多个-defined名称是等效的。
干杯和健康。-Alf 2010年

啊,我明白了。谢谢。
Jack Harvin 2010年

4
+1为问题2的答案-非常清楚。其余的答案也很清楚,但是一个对我来说很突出:-)
Michael van der Westhuizen 2012年

33

没有这个typedef词,在C ++中,声明将声明FunctionFunc类型为无参数函数指针的变量,返回void

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


5
这是思考的一种非常好的方法。如果您仔细阅读其他答案,它们并不能真正解决OP对别名和名称纠缠的困惑。通过阅读这篇文章,我学到了一些新东西。
疯狂物理学家

9

如果可以使用C ++ 11,则可能要使用std::functionand using关键字。

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

1
没有C ++ 11 using关键字就好了typedef std::function<void(int, std::string)> FunctionFunc;,以防万一有人想为没有C ++ 11的函数提供另一个包装
顶级大师

2
#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) );
}

1
在什么情况下需要'&'?例如,“ func_p =&findDistance”和“ func_p = findDistance”是否同样有效?
唐娜

1
函数名称是一个指针,因此您无需对其使用“&”。换句话说,当考虑函数指针时,“&”是可选的。但是,对于原始数据类型,您需要使用'&'来获取其地址。
Amjad

1
'&'可以是可选的总是让人感到奇怪。如果使用typedef创建指向原语的指针(即typedef (*double) p'&'是否可选?
Donna

我认为您想输入typedef double* p以定义指向double的指针。如果p要从原始变量填充指针,则需要使用“&”。附带说明,我们** <指针名称>取消引用指针。的*是在函数指针取消引用指针(功能名),并转到其中函数说明位于存储器的块使用。
阿姆贾德(Amjad)

2

对于语法的一般的情况下,你可以看看ANSI C标准的附录A中

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

在类型中,declaration-specifiers您可以看到可以混合许多说明符类型,其顺序无关紧要。

例如,正确地说:

long typedef long a;

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.