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

如何在C中声明常量函数指针数组?,c,arrays,pointers,constants,function-pointers,C,Arrays,Pointers,Constants,Function Pointers,我需要声明一个指向函数的指针数组,如下所示: extern void function1(void); extern void function2(void); ... void (*MESSAGE_HANDLERS[])(void) = { function1, function2, ... }; 但是,我希望数组被声明为常量——数组中的数据和指向数据的指针。不幸的是,我不记得在哪里放置const关键字 我假设实际指针,即本例中的MESSAGE_HANDLERS,已经是常

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

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

void (*MESSAGE_HANDLERS[])(void) = {
   function1,
   function2,
   ...
};
但是,我希望数组被声明为常量——数组中的数据和指向数据的指针。不幸的是,我不记得在哪里放置const关键字


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

在这种情况下,请使用
typedef
来命名函数签名,这会使它简单得多:

typedef void MESSAGE_HANDLER(void);
有了这一点,就应该:

MESSAGE_HANDLER * const handlers[] = { function1, function2 };
获取数组常量的实际内容


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

使用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;
}

cdecl
说:

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

这是您需要的吗?

我不确定这在“C”中是否有效。它在“C++”中确实有效:

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

    typedef void(*MESSAGE_HANDLER)()

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

    MESSAGE_HANDLER const handlers[]={function1,function2}


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

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

如何在没有帮助的情况下申报这些东西? 阵列 是一个5 T的数组。要使T成为函数类型,请在左侧写入返回类型,在右侧写入参数:

void t[5](void);
将是一个由5个函数组成的数组,返回void,不带参数。但是函数本身不能填充在数组中!它们不是物体。只有指向它们的指针可以

那怎么办

void * t[5](void);
这仍然是错误的,因为它只会将返回类型更改为指向void的指针。必须使用括号:

void (*t[5])(void);
这实际上是可行的。t是一个由5个指针组成的数组,指向返回void且不带参数的函数

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

int (*t[5])[3];
就这样!指向3 int数组的5个指针数组

功能呢? 我们刚刚学到的关于函数的知识也是正确的。让我们声明一个接受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];
这是一个接受int的函数,返回指向3 int数组的指针

这和const有什么关系? 既然上面解释了如何从基本类型构建complexer类型,您可以将
const
放在您现在知道它们所属的位置。试想一下:

T c * c * c ... * c name;
T
是我们最后指向的基本类型。
c
表示常量或非常量。比如说

int const * const * name;
将声明名称以使类型指针指向常量int。您可以更改
名称
,但不能更改
*名称
,该类型为

int const * const
int const
也不是
**name
,类型为

int const * const
int const
让我们将其应用于上面的函数指针:

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

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

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

是的,这正是我所需要的。我不知道cdecl(和c++decl)程序。谢谢你的提示。cdecl非常好。谢谢你把这件事告诉我,对不起,伙计。起初我有常数,但不知怎的我删除了它。现在它又出现了,我扩展了它以更详细地解释它。谢谢!这是一个很好的解释。我不确定,但您可能应该将const关键字放在按摩处理程序之后。无论如何,这个答案应该更高,typedef是避免混淆的方法@Vincent
T const
const T
是相同的(其中T是标识类型的标识符)。你是正确的,<代码> T const 被许多人认为是更一致的。注意很多人认为指针类型DEFS有点模糊;这里不需要在typedef中包含指针,例如
typedef void处理程序(void);处理函数func1,func2;Handler*const handlers[]={func1,func2}。这不是声明了一个指向常量函数的指针数组吗?