代码之家  ›  专栏  ›  技术社区  ›  Judge Maygarden

如何在C中声明常量函数指针数组?

  •  22
  • Judge Maygarden  · 技术社区  · 16 年前

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

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

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

    我假设实际的指针(本例中的消息处理程序)已经是常量,因为它声明为数组。另一方面,如果数组中的函数指针声明为如图所示,那么它在运行时不能被更改吗?

    5 回复  |  直到 16 年前
        1
  •  56
  •   Johannes Schaub - litb    16 年前

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

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

    数组

    T t[5];
    

    是一个 5 T阵列 . 要使t成为函数类型,您可以将返回类型写在左侧,参数写在右侧:

    void t[5](void);
    

    是一个 返回void且不带参数的5个函数数组 . 但是函数本身不能填充在数组中!它们不是物体。只有指向它们的指针才能。

    怎么样

    void * t[5](void);
    

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

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

    这实际上是可行的。 t是返回void且不带参数的函数的5个指针数组。 .

    伟大的!一个指向数组的指针数组怎么样?这很相似。元素类型显示在左侧,尺寸标注显示在右侧。同样,需要括号,因为否则数组将成为一个整数指针的多维数组:

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

    就是这样!安 指向3 int数组的5个指针数组 .

    功能呢?

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

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

    我们需要括号,因为他和上面的理由一样。我们现在可以调用它,并调用再次指向的返回函数。

    f(10)();
    

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

    这个怎么样?

    f(10)(true)(3.4);
    

    ?换句话说,一个 函数taking int返回指向函数taking bool的指针返回指向函数taking double并返回void的指针 看起来像吗?答案是你只是把它们筑巢:

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

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

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

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

    这和警察有什么关系?

    既然上面解释了如何从基本类型构建complexer类型,那么您可以 const 在你现在知道他们属于哪里的地方。试想一下:

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

    这个 T 是我们在结尾处指向的基本类型。这个 c 代表const或not const。例如

    int const * const * name;
    

    将声明名称具有类型 指向常量的指针指向常量int的指针 . 你可以改变 name 但是你不能改变 *name ,类型为

    int const * const
    

    而且两者都不 **name ,类型为

    int const
    

    让我们将此应用于上面的函数指针:

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

    这实际上会声明数组包含常量指针。因此,在创建(并初始化)数组之后, 指针 是警察,因为 康斯特 出现在星星后面。注意,我们不能 康斯特 在这个例子中,在星星之前,因为 没有指向常量函数的指针 . 函数不能是常量,因为这不合理。因此以下内容无效:

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

    结论

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

        2
  •  15
  •   qrdl    16 年前

    cdecl 说:

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

    这是你需要的吗?

        3
  •  15
  •   unwind    8 年前

    在这种情况下,做一个 typedef 要命名函数签名,这就简单得多:

    typedef void MESSAGE_HANDLER(void);
    

    有了它,应该是:

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

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

    编辑 :从中删除指针部分 类型定义 这真的更好(活到老学到老)。

        4
  •  1
  •   David Norman    16 年前

    使用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
  •  1
  •   Delimitry COLD TOLD    8 年前

    我不确定这是否适用于“c”。它在“C++”中起作用:

    • 首先将消息处理程序定义为类型:

      typedef void (*MESSAGE_HANDLER)();

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

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

    诀窍在于 typedef ,如果您可以在“c”中做相同的语义,它也应该工作。