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

发布于 2024-07-09 21:40:14 字数 358 浏览 8 评论 0原文

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

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

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

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

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

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).

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

瀟灑尐姊 2024-07-16 21:40:14

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

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

Arrays

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];

这是一个采用 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(其类型为 Let's 类型),

int const * const

也不能更改 **name(其类型为

int const

Let's)将其应用于上面的函数指针:

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

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

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

结论

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

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:

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.

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:

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

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

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.

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:

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:

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

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:

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

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

int const * const

and neither **name, which would be of type

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:

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.

美人如玉 2024-07-16 21:40:14

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

typedef void MESSAGE_HANDLER(void);

有了它,它应该只是:

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

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

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

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

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).

丘比特射中我 2024-07-16 21:40:14

cdecl 说:

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

这是你需要的吗?

cdecl says:

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

Is it what you need?

﹎☆浅夏丿初晴 2024-07-16 21:40:14

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

With VisualStudio 2008, I get:

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;
}
捶死心动 2024-07-16 21:40:14

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

  • 首先将 MESSAGE_HANDLERS 定义为类型:

    typedef void (*MESSAGE_HANDLER)();

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

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

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

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

  • First define MESSAGE_HANDLERS as a type:

    typedef void (*MESSAGE_HANDLER)();

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

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文