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

时间:2008-12-03 15:11:26

标签: c arrays pointers const function-pointers

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

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

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

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

我假设在这种情况下实际指针MESSAGE_HANDLERS已经是常量,因为它被声明为数组。另一方面,如果声明如图所示,那么数组中的函数指针是否可以在运行时更改?

5 个答案:

答案 0 :(得分:56)

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

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

阵列

T t[5];

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

void t[5](void);

是一个包含5个函数的数组,返回void且不带参数。但是函数本身不能填充数组!它们不是对象。只有指向它们的指针才可以。

怎么样?
void * t[5](void);

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

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

这实际上会有效。 t是一个包含5个指向函数的数组,这些函数返回void并且不带参数

大!一系列指向阿拉斯的指针怎么样?这非常相似。元素类型显示在左侧,维度显示在右侧。同样,需要括号,因为否则数组将成为整数指针的多维数组:

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

就是这样!一个5 em指向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];

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

它与const有什么关系?

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

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

T是我们最后指向的基本类型。 c代表const或not 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声明函数和数组的方式实际上实际上有点令人困惑。你必须首先考虑它,但如果你理解它,你可以使用它编写非常紧凑的函数声明。

答案 1 :(得分:15)

在这种情况下,执行typedef来命名您的函数签名,这样可以简化:

typedef void MESSAGE_HANDLER(void);

有了它,它应该只是:

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

使数组的实际内容保持不变。

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

答案 2 :(得分:15)

cdecl说:

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

这是你需要的吗?

答案 3 :(得分:1)

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

答案 4 :(得分:1)

我不确定这是否适用于'C'。它确实在'C ++'中起作用:

  • 首先将MESSAGE_HANDLERS定义为类型:

    typedef void (*MESSAGE_HANDLER)();

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

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

诀窍在于typedef,如果你可以在'C'语义上做同样的事情,它也应该有效。