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

时间:2022-05-27 07:39:33

I need to declare an array of pointers to functions like so:

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

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

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

However, I want the the array to be declared as constant -- both the data in the array and the pointer to the data. Unfortunately, I do not recall where to place the const key-word(s).

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

I'm assuming the actual pointer, MESSAGE_HANDLERS in this case, is already constant because it is declared as an array. On the otherhand, couldn't the function pointers within the array be change at runtime if it is declared as shown?

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

5 个解决方案

#1


55  

There is a technique to remember how to build such type. First try to read pointers starting from their name and read from right to left.

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

How to declare that stuff without help?

Arrays

T t[5];

is an array of 5 T. To make T a function type, you write the return-type to the left, and the parameters to the right:

是一个5 T的数组,为了使T成为函数类型,你在左边写return-type,在右边写参数:

void t[5](void);

would be an array of 5 functions returning void and taking no parameters. But functions itself can't be stuffed in arrays! They are not objects. Only pointers to them can.

将是一个由5个函数组成的数组,返回void,不接受任何参数。但是函数本身不能填充到数组中!他们不是对象。只有指向它们的指针可以。

What about

是什么

void * t[5](void);

That's still wrong as it would just change the return-type to be a pointer to void. You have to use parentheses:

这仍然是错误的,因为它只会改变return类型,从而成为一个指向void的指针。你必须用括号:

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

and this will actually work. t is an array of 5 pointers to functions returning void and taking no parameters.

这是可行的。t是一个由5个指针组成的数组,这些指针指向返回void且不接受任何参数的函数。

Great! What about an array of pointers to arras? That's very similar. The element type appears at the left, and the dimension at the right. Again, parentheses are needed because otherwise the array would become a multidimensional array of integer pointers:

太棒了!给阿拉斯一个指针数组怎么样?这是非常相似的。元素类型出现在左边,维度出现在右边。同样,需要括号,因为否则数组将成为一个多维的整数指针数组:

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

That's it! An array of 5 pointers to arrays of 3 int.

就是这样!一个5个指向3个int的数组的数组。

What about functions?

What we have just learned is true about functions too. Let's declare a function taking an int that returns a pointer to another function taking no parameter and returning void:

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

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

we need parentheses again for he same reason as above. We could now call it, and call the returned function pointed to again.

同样的原因,我们需要括号。我们现在可以调用它,并再次调用返回的函数。

f(10)();

Returning a pointer to function returning another pointer to function

What about this?

这是什么?

f(10)(true)(3.4);

? In other words, how would a function taking int returning a pointer to a function taking bool returning a pointer to a function taking double and returning void would look like? The answer is that you just nest them:

吗?换句话说,如果函数取int返回一个函数的指针,而取bool返回一个函数的指针取double返回void会是什么样子?答案是你把它们嵌在一起:

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

You could do so endless times. Indeed, you can also return a pointer to an array just like you can a pointer to a function:

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

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

This is a function taking int returning a pointer to a function taking bool returning a pointer to an array of 3 int

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

What does it have to do with const?

Now that the above explained how to build up complexer types from fundamental types, you can put const at places where you now know where they belong to. Just consider:

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

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

The T is the basic type that we end up pointing to at the end. The c stands for either const or not const. For example

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

int const * const * name;

will declare name to have the type pointer to a constant pointer to a constant int. You can change name, but you cannot change *name, which would be of type

将声明name具有指向常量int的类型指针。您可以更改名称,但不能更改*name,这将是类型

int const * const

and neither **name, which would be of type

以及**name,它们都不是类型

int const

Let's apply this to a function pointer of above:

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

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

This would actually declare the array to contain constant pointers. So after creating (and initializing) the array, the pointers are const, because the const appeared after the star. Note that we cannot put a const before the star in this case, since there are no pointers to constant functions. Functions simply can't be const as that would not make sense. So the following is not valid:

这实际上会声明数组包含常量指针。所以在创建(和初始化)数组之后,指针是const,因为const出现在星形之后。注意,在这种情况下,我们不能在恒星前面加上const,因为没有指向常数函数的指针。简单的功能是不可能的,因为那是没有意义的。因此,以下是无效的:

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

Conclusion

The C++ and C way of declaring functions and arrays actually is actually a bit confusing. You have to get your head around it first, but if you understand it, you can write very compact function declarations using it.

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

#2


15  

In situations like this, do a typedef to name your function signature, that makes it far simpler:

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

typedef void MESSAGE_HANDLER(void);

with that in place, it should be just:

在这种情况下,它应该是:

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

To get the actual content of the array constant.

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

EDIT: Removed pointer part from the typedef, this really is better (live and learn).

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

#3


14  

cdecl says:

cdecl说:

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

Is it what you need?

这是你需要的吗?

#4


1  

With VisualStudio 2008, I get:

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

I am not sure if this will work in 'C'. it does work in 'C++':

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

  • First define MESSAGE_HANDLERS as a type:

    首先将MESSAGE_HANDLERS定义为类型:

    typedef void (*MESSAGE_HANDLER)();

    typedef无效(* MESSAGE_HANDLER)();

  • Then, use the type definition to declare your array a constant:

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

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

    MESSAGE_HANDLER const处理程序[]= {function1, function2};

The trick is in the typedef, if you can do the same semantically in 'C', it should work too.

诀窍就在typedef中,如果您可以在“C”中使用相同的语义,那么它也应该可以工作。

#1


55  

There is a technique to remember how to build such type. First try to read pointers starting from their name and read from right to left.

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

How to declare that stuff without help?

Arrays

T t[5];

is an array of 5 T. To make T a function type, you write the return-type to the left, and the parameters to the right:

是一个5 T的数组,为了使T成为函数类型,你在左边写return-type,在右边写参数:

void t[5](void);

would be an array of 5 functions returning void and taking no parameters. But functions itself can't be stuffed in arrays! They are not objects. Only pointers to them can.

将是一个由5个函数组成的数组,返回void,不接受任何参数。但是函数本身不能填充到数组中!他们不是对象。只有指向它们的指针可以。

What about

是什么

void * t[5](void);

That's still wrong as it would just change the return-type to be a pointer to void. You have to use parentheses:

这仍然是错误的,因为它只会改变return类型,从而成为一个指向void的指针。你必须用括号:

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

and this will actually work. t is an array of 5 pointers to functions returning void and taking no parameters.

这是可行的。t是一个由5个指针组成的数组,这些指针指向返回void且不接受任何参数的函数。

Great! What about an array of pointers to arras? That's very similar. The element type appears at the left, and the dimension at the right. Again, parentheses are needed because otherwise the array would become a multidimensional array of integer pointers:

太棒了!给阿拉斯一个指针数组怎么样?这是非常相似的。元素类型出现在左边,维度出现在右边。同样,需要括号,因为否则数组将成为一个多维的整数指针数组:

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

That's it! An array of 5 pointers to arrays of 3 int.

就是这样!一个5个指向3个int的数组的数组。

What about functions?

What we have just learned is true about functions too. Let's declare a function taking an int that returns a pointer to another function taking no parameter and returning void:

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

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

we need parentheses again for he same reason as above. We could now call it, and call the returned function pointed to again.

同样的原因,我们需要括号。我们现在可以调用它,并再次调用返回的函数。

f(10)();

Returning a pointer to function returning another pointer to function

What about this?

这是什么?

f(10)(true)(3.4);

? In other words, how would a function taking int returning a pointer to a function taking bool returning a pointer to a function taking double and returning void would look like? The answer is that you just nest them:

吗?换句话说,如果函数取int返回一个函数的指针,而取bool返回一个函数的指针取double返回void会是什么样子?答案是你把它们嵌在一起:

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

You could do so endless times. Indeed, you can also return a pointer to an array just like you can a pointer to a function:

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

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

This is a function taking int returning a pointer to a function taking bool returning a pointer to an array of 3 int

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

What does it have to do with const?

Now that the above explained how to build up complexer types from fundamental types, you can put const at places where you now know where they belong to. Just consider:

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

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

The T is the basic type that we end up pointing to at the end. The c stands for either const or not const. For example

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

int const * const * name;

will declare name to have the type pointer to a constant pointer to a constant int. You can change name, but you cannot change *name, which would be of type

将声明name具有指向常量int的类型指针。您可以更改名称,但不能更改*name,这将是类型

int const * const

and neither **name, which would be of type

以及**name,它们都不是类型

int const

Let's apply this to a function pointer of above:

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

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

This would actually declare the array to contain constant pointers. So after creating (and initializing) the array, the pointers are const, because the const appeared after the star. Note that we cannot put a const before the star in this case, since there are no pointers to constant functions. Functions simply can't be const as that would not make sense. So the following is not valid:

这实际上会声明数组包含常量指针。所以在创建(和初始化)数组之后,指针是const,因为const出现在星形之后。注意,在这种情况下,我们不能在恒星前面加上const,因为没有指向常数函数的指针。简单的功能是不可能的,因为那是没有意义的。因此,以下是无效的:

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

Conclusion

The C++ and C way of declaring functions and arrays actually is actually a bit confusing. You have to get your head around it first, but if you understand it, you can write very compact function declarations using it.

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

#2


15  

In situations like this, do a typedef to name your function signature, that makes it far simpler:

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

typedef void MESSAGE_HANDLER(void);

with that in place, it should be just:

在这种情况下,它应该是:

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

To get the actual content of the array constant.

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

EDIT: Removed pointer part from the typedef, this really is better (live and learn).

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

#3


14  

cdecl says:

cdecl说:

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

Is it what you need?

这是你需要的吗?

#4


1  

With VisualStudio 2008, I get:

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

I am not sure if this will work in 'C'. it does work in 'C++':

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

  • First define MESSAGE_HANDLERS as a type:

    首先将MESSAGE_HANDLERS定义为类型:

    typedef void (*MESSAGE_HANDLER)();

    typedef无效(* MESSAGE_HANDLER)();

  • Then, use the type definition to declare your array a constant:

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

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

    MESSAGE_HANDLER const处理程序[]= {function1, function2};

The trick is in the typedef, if you can do the same semantically in 'C', it should work too.

诀窍就在typedef中,如果您可以在“C”中使用相同的语义,那么它也应该可以工作。