指向函数/函数表的指针

Pointers to functions / Function Tables

本文关键字:函数 指针      更新时间:2023-10-16

我正在学习函数指针,并遇到了以下代码:

#include <iostream>
using namespace std;
// A macro to define dummy functions:
#define DF(N) void N() { 
    cout << "function " #N " called ... " << endl; }
DF(a); DF(b); DF(c); DF(d); DF(e); DF(f); DF(g);
void (*func_table[])() = {a, b, c, d, e, f, g}; 
int main(){
    while(1){
        cout << "press a key from 'a' to 'g' " 
        "or q to quit"<< endl;
        char c, cr;
        cin.get(c); cin.get(cr); // second one for CR
        if ( c == 'q')
        break;
        if (c < 'a' || c > 'g')
        continue;
        (*func_table[c-'a'])();
    }
}

有人可以向我解释指向函数func_table的指针是如何工作的吗?特别是{}内有a,b,c,d,e,f,g的效果是什么,整个表达式在做什么?

通常,当我看到指向函数的指针时,您可以通过分配函数名称来初始化指针,但在此示例中,它仅提供字符数组。那么它怎么知道调用DF(char(呢?

另外,我不确定为什么我需要这些语句:

DF(a); DF(b); DF(c); DF(d); DF(e); DF(f); DF(g);

另外,声明:(*func_table[c-'a'])();我们减去"a"的原因是,这种不同将确定从数组中选择的正确字母{a,b,c,d,e,f,g}

这是一些丑陋的、混淆的代码,这并不丢人,它让你感到困惑。让我们一点一点地做:

// A macro to define dummy functions:
#define DF(N) void N() { 
    cout << "function " #N " called ... " << endl; }
DF(a); 

如果展开该宏调用,则会得到:

void a() { 
    cout << "function a called ... " << endl; }

对于 b、c 等类似。因此,ag都是打印自己名称的函数,仅此而已。

void (*func_table[])() = {a, b, c, d, e, f, g}; 

使用typedef更容易阅读:

typedef void (*FuncPtr)(); //FuncPtr is a function pointer to functions of type void X();
FuncPtr func_table[] = {a, b, c, d, e, f, g};

实际上,这是{&a, &b, &c, &d, &e, &f, &g} - 作者使用了隐式函数到函数指针的转换。含义:func_table 是指向a g的函数指针数组

int main(){
    while(1){
        cout << "press a key from 'a' to 'g' " 
        "or q to quit"<< endl;
        char c, cr;
        cin.get(c); cin.get(cr); // second one for CR
        if ( c == 'q')
        break;
        if (c < 'a' || c > 'g')
        continue;

这应该很清楚。现在调用:

    (*func_table[c-'a'])();

c-'a' 是与 'a' 的偏移量,表示 0 表示 'a',1 表示 'b' 等等。例如,如果 c 是 'd',则此行调用 (*func_table['d'-'a'])() ,wich 是 *(func_table[3])() wich 只是 d - 因此该行仅使用您刚刚键入的名称调用函数。

通常当我看到指向函数的指针时,您会初始化指针 通过分配函数名称,但在本例中它只是 提供字符数组。那么它怎么知道打电话 DF(字符(?

实际上,它不是给出一个字符数组,而是一个函数数组。 DF(a)将定义一个命名为 a 的函数。

所以基本上,你最终会有一个指向你的函数的函数指针数组(即,abc、...(。

我们减去"a"的原因是,如果用户按下b键,我们将需要调用b函数。您的变量c将以"b"作为值。"b" - "a" = 1。因此,它将调用数组的第二个函数指针(因为 array[1] 是第二个元素(,这实际上是命名为 b 的函数。

丑陋的丑陋...

DF(N)创建一个输出"N"的 N 函数(在宏中使用 # 运算符(

所以:

 DF(a);

是一种较短的写作方式

 void a(){cout << "function Acalled" << endl;}

现在它们存储在一个数组中:

func_table[0]() 

相当于

a()

使用字符c-'a'会在两个字符之间产生差异:'a' - 'a' = 0

然后调用func_tables[c-'a']将调用预期的函数。

这一行:

#define DF(N) void N() { 
    cout << "function " #N " called ... " << endl; }

定义一个名为 N 的新函数。这是有效的,因为宏只是创建一个文本替换,所以当编译器看到它时,它会看到一个名为 N 的完全有效的函数,就好像你键入了该函数一样

 void a() {... }

这里有用上述宏声明的函数,名为a-g

DF(a); DF(b); DF(c); DF(d); DF(e); DF(f); DF(g);

这里:

void (*func_table[])() = {a, b, c, d, e, f, g}; 

上面声明的函数只是简单地分配。

减去字符的原因是将索引 0-n 放入函数数组中。