25

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

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

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

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

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

4

5 回答 5

59

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

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

数组

T t[5];

是一个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];

就是这样!一个由 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;

TheT是我们最后指向的基本类型。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请注意,在这种情况下,我们不能在星号之前放置 a ,因为没有指向常量函数的指针。函数根本不能是 const ,因为那没有意义。因此以下内容无效:

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

结论

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

于 2008-12-03T16:26:53.273 回答
16

在这种情况下,请执行 atypedef来命名您的函数签名,这样会更简单:

typedef void MESSAGE_HANDLER(void);

有了这个,它应该是:

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

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

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

于 2008-12-03T15:23:01.017 回答
15

cdecl说:

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

这是你需要的吗?

于 2008-12-03T15:25:11.293 回答
1

使用 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;
}
于 2008-12-03T15:24:53.087 回答
1

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

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

    typedef void (*MESSAGE_HANDLER)();

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

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

诀窍在于typedef,如果您可以在“C”中在语义上执行相同的操作,它也应该可以工作。

于 2008-12-03T15:38:25.680 回答