【问题标题】:Pointers to functions / Function Tables指向函数/函数表的指针
【发布时间】:2013-07-15 07:57:42
【问题描述】:

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

#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}中选择的正确字母?

【问题讨论】:

    标签: c++ arrays pointers macros c-preprocessor


    【解决方案1】:

    那是一些丑陋的混淆代码,它让你感到困惑并不可惜。让我们一块一块地做:

    // 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};
    

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

    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'])(),至于 *(func_table[3])(),至于 d - 因此该行仅使用您刚刚输入的名称调用函数。

    【讨论】:

    • 我想我现在明白了。因此宏#define DF(N) void N() { / .... 将创建一个名为 (N) 的新函数,因此 DF(a) = a()。由于我们将没有参数列表的函数名传递给函数指针,这就是为什么我们有函数数组 {a,b,c,d,e,f,g} 实际上是 {a(), b(), c (), d(), e(), f(), g()} 感谢您的耐心和愿意解释代码我真的很感激。 - 马可
    • 其实函数指针数组是{&amp;a, &amp;b, &amp;c, &amp;d, &amp;e, &amp;f, &amp;g}——作者利用了函数到函数指针的隐式转换。 {a(), b(), c()} 将是一个函数调用结果数组。
    【解决方案2】:

    通常当我看到一个指向函数的指针时,你会初始化指针 通过分配函数名称,但在这个例子中,它只是 提供一个字符数组。那么它怎么知道调用 DF(char)?

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

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

    我们减去“a”的原因是,如果用户按下b 键,我们将要调用b 函数。 您的变量 c 将具有 'b' 作为值。 'b' - 'a' = 1。因此它将调用数组的第二个函数指针(因为 array[1] 是第二个元素),这确实是名为 b 的函数。

    【讨论】:

      【解决方案3】:

      丑丑...

      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'] 将调用预期的函数。

      【讨论】:

        【解决方案4】:

        这一行:

        #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。

        【讨论】:

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