【问题标题】:How does one declare an array of constant function pointers in C?如何在 C 中声明一组常量函数指针?
【发布时间】:2010-09-25 03:29:58
【问题描述】:

我需要声明一个指向函数的指针数组,如下所示:

extern void function1(void);
extern void function2(void);
...

void (*MESSAGE_HANDLERS[])(void) = {
   function1,
   function2,
   ...
};

但是,我希望将数组声明为常量——数组中的数据和指向数据的指针。不幸的是,我不记得在哪里放置 const 关键字。

我假设实际的指针 MESSAGE_HANDLERS 在这种情况下已经是常量,因为它被声明为一个数组。另一方面,如果数组中的函数指针被声明为如图所示,难道不能在运行时改变它吗?

【问题讨论】:

    标签: c arrays pointers constants function-pointers


    【解决方案1】:

    有一种技术可以记住如何构建这种类型。首先尝试从名称开始读取指针,并从右向左读取。

    如何在没有帮助的情况下声明这些东西?

    数组

    T t[5];
    

    是一个 5 个 T 的数组。要使 T 成为函数类型,请将返回类型写在左边,将参数写在右边:

    void t[5](void);
    

    是一个返回 void 且不带参数的 5 个函数的数组。但是函数本身不能塞进数组中!它们不是对象。只有指向它们的指针可以。

    怎么样

    void * t[5](void);
    

    这仍然是错误的,因为它只会将返回类型更改为指向 void 的指针。您必须使用括号:

    void (*t[5])(void);
    

    这实际上会起作用。 t 是一个包含 5 个指针的数组,指向返回 void 且不带参数的函数

    太棒了!指向 arras 的指针数组呢?这非常相似。元素类型显示在左侧,尺寸显示在右侧。同样,需要括号,否则数组将成为整数指针的多维数组:

    int (*t[5])[3];
    

    就是这样! 一个由 5 个指针组成的数组,指向 3 个 int 的数组

    函数呢?

    我们刚刚学到的关于函数的知识也是正确的。让我们声明一个带有 int 的函数,它返回指向另一个不带参数并返回 void 的函数的指针:

    void (*f(int))(void);
    

    出于与上述相同的原因,我们再次需要括号。我们现在可以调用它,并再次调用返回的函数指向。

    f(10)();
    

    返回一个指向函数的指针返回另一个指向函数的指针

    这个呢?

    f(10)(true)(3.4);
    

    ?换句话说,一个采用 int 的函数返回一个指向一个采用 bool 的函数的指针返回一个指向一个采用 double 并返回 void 的函数的指针的函数会是什么样子?答案是你只是嵌套它们:

    void (*(*f(int))(bool))(double);
    

    你可以无休止地这样做。实际上,您也可以返回指向数组的指针,就像返回指向函数的指针一样:

    int (*(*f(int))(bool))[3];
    

    这是一个函数,返回一个指向函数的指针,返回一个指向一个函数的函数,返回一个指向 3 个 int 数组的指针

    和 const 有什么关系?

    现在上面解释了如何从基本类型构建更复杂的类型,您可以将const 放在您现在知道它们所属的位置。考虑一下:

    T c * c * c ... * c name;
    

    T 是我们最后指向的基本类型。 c 代表 const 或非 const。例如

    int const * const * name;
    

    将声明 name 的类型为 指向一个常量指针的指针,该指针指向一个常量 int。可以更改name,但不能更改*name,类型为

    int const * const
    

    也不是**name,它的类型是

    int const
    

    让我们把它应用到上面的函数指针上:

    void (* const t[5])(void);
    

    这实际上会声明数组包含常量指针。所以在创建(和初始化)数组之后,指针是常量,因为const出现在星号之后。请注意,在这种情况下,我们不能在星号之前放置const,因为没有指向常量函数的指针。函数根本不能是 const ,因为那没有意义。因此以下内容无效:

    void (const * t[5])(void);
    

    结论

    C++ 和 C 声明函数和数组的方式实际上有点令人困惑。您必须首先了解它,但如果您理解它,您可以使用它编写非常紧凑的函数声明。

    【讨论】:

    • 对不起,伙计。最初我有 const ,但不知何故我删除了它。它现在又出现了,我对其进行了扩展以更详细地解释它。
    • 谢谢!这是一个很好的解释。
    【解决方案2】:

    在这种情况下,使用typedef 来命名您的函数签名,这样会更简单:

    typedef void MESSAGE_HANDLER(void);
    

    有了它,它应该是:

    MESSAGE_HANDLER * const handlers[] = { function1, function2 };
    

    获取数组常量的实际内容。

    编辑:从typedef 中删除了指针部分,这确实更好(生活和学习)。

    【讨论】:

    • 我不确定,但您可能应该将 const 关键字放在 MASSAGE_HANDLER 之后。无论如何,这个答案应该更高,typedefs是避免混淆的方法!
    • @Vincent T constconst T 是相同的(其中 T 是标识类型的标识符)。没错,T const 被许多人认为更一致。
    • 请注意,许多人认为指针类型定义有些混淆;您不需要在此处的 typedef 中包含指针,例如typedef void Handler(void); Handler func1, func2; Handler * const handlers[] = { func1, func2 };.
    【解决方案3】:

    cdecl 说:

    cdecl> explain void (* const foo[])(void)
    declare foo as array of const pointer to function (void) returning void
    

    这是你需要的吗?

    【讨论】:

    • 是的,这正是我所需要的。我不知道 cdecl(和 c++decl)程序。感谢您的提示。
    • cdecl 非常好。感谢您将其纳入 SO 知识。
    【解决方案4】:

    使用 VisualStudio 2008,我得到:

    void (* const MESSAGE_HANDLERS[])(void) = {
       NULL,
       NULL
    };
    
    int main ()
    {
        /* Gives error 
            '=' : left operand must be l-value
        */
        MESSAGE_HANDLERS = NULL;
    
        /* Gives error 
            l-value specifies const object
        */
        MESSAGE_HANDLERS[0] = NULL;
    }
    

    【讨论】:

      【解决方案5】:

      我不确定这是否适用于“C”。它确实适用于“C++”:

      • 首先将 MESSAGE_HANDLERS 定义为一个类型:

        typedef void (*MESSAGE_HANDLER)();

      • 然后,使用类型定义将数组声明为常量:

        MESSAGE_HANDLER const handlers[] = {function1, function2};

      诀窍在typedef 中,如果你可以在“C”中做同样的语义,它也应该可以工作。

      【讨论】:

      • 这不是声明了一个指向 const 函数的指针数组吗?
      猜你喜欢
      • 2011-04-01
      • 2012-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-16
      • 1970-01-01
      • 2010-11-20
      • 2011-01-13
      相关资源
      最近更新 更多