简体   繁体   English

在C中评估结构成员访问的功能指针?

[英]Evaluate a Function Pointer on Structure Member Access in C?

I have a problem to solve that would basically just disappear if I could have a member of a struct evaluate to the result of a function when accessed. 我有一个问题要解决,如果我可以让一个结构的成员在访问时对函数的结果求值,那基本上就消失了。 I don't think I've ever seen any examples of this kind of behavior -- In fact I have a suspicion that what I'm looking for would violate some deep rules of C if not programming in general. 我认为我从未见过此类行为的任何示例-实际上,我怀疑如果不进行一般编程,我所寻找的内容将违反一些深层的C规则。 If that's the case I'd certainly appreciate hearing it from someone with a little more evidence/experience to explain why. 如果是这样,我当然会很高兴听到有更多证据/经验的人来解释为什么。

Here's some simplified code as an example: 以下是一些简化的代码作为示例:

/* state.c */

#include "state.h"

state_t state_ctx;
/* state.h */

typedef struct _state_t {
    foo_t foo;
}state_t;

extern state_t state_ctx;

#define ACCESS_STATE(x) (state_ctx.x)
/* main.c */

const bar_t bar{
    .baz = ACCESS_STATE(foo); // Types are compatible
}

In English there's a global state variable that has a convenient way to redefine access, and that access method is used inside an initializer list for a global variable in the .c file of interest. 用英语说,有一个全局状态变量,它具有一种方便的方法来重新定义访问,并且该访问方法用于感兴趣的.c文件中的全局变量的初始化列表内。

That code works, but my mission is to allow to switch contexts from one state variable to another. 该代码有效,但是我的任务是允许将上下文从一个状态变量切换到另一个状态变量。 I can easily change the state definitions to something like: 我可以轻松地将状态定义更改为:

/* state.c */

#include "state.h"

state_t* p_current_state_ctx; // Now a pointer id's the current state structure
/* state.h */

typedef struct _state_t {
    baz_t foo;
}state_t;

extern state_t* p_current_state_ctx;

#define ACCESS_STATE(x) (p_current_state_ctx->x)

All I need to do to switch contexts is set the current state pointer. 切换上下文所需要做的只是设置当前状态指针。 Nice. 尼斯。 But one problem - the initializer lists require the ACCESS_STATE(x) macro to evaluate to a constant. 但是有一个问题-初始化程序列表需要ACCESS_STATE(x)宏才能将其求值为常量。 I thought it was brilliant to define a function like: 我认为定义这样的函数真是太棒了:

foo_t func_to_get_foo( void ){
    return p_current_state_ctx->foo;
}

So that the main.c initializer could be re-written as: 这样main.c初始化程序可以重写为:

/* main.c */

const bar_t bar{
    .baz = (foo_t)&func_to_get_foo; // Trying to get current state's foo
                                    // Obviously this cast isn't generally correct
                                    // and only compiles if the types are pointers
                                    // but still the behavior is wrong
}

Because the function pointer would be a constant expression. 因为函数指针将是一个常量表达式。 But as I wrote it out my heart deflated because I realized that of course now baz would just be the pointer to func_to_get_foo and not the value of foo like I had fantasized. 但是,当我写下来时,我的心func_to_get_foo ,因为我意识到,现在当然baz只是指向func_to_get_foo的指针,而不是我幻想的foo值。

The actual program I'm working with is pretty complicated and I'm still learning it's ins and outs. 我正在使用的实际程序非常复杂,而且我仍在学习它的来龙去脉。 I want to make as few modifications as I can while still getting the multi-state ability. 我希望在获得多状态功能的同时进行尽可能少的修改。 There are a lot of instances of initializer list variables like the bar example so I'd prefer to avoid writing context-switching code for each one. 初始化程序列表变量有很多实例,例如bar示例,因此我宁愿避免为每个实例编写上下文切换代码。

So if there was some magic that could cause the result of func_to_get_foo() to appear as the result of accessing bar.baz I'd be ecstatic. 因此,如果有某种魔术可能导致由于访问bar.baz而导致func_to_get_foo()的结果出现,我会欣喜若狂。 Does anyone have any advice on how to easily accomplish this? 有人对如何轻松完成此操作有任何建议吗?

If there's no way to do that then of course I'd be interested to hear some theory as to why... Or is it cut and dry 'thats just not a feature of C?' 如果没有办法做到这一点,那么我当然很想听听一些关于为什么的理论……或者它是干切的“那不是C的功能吗?”

And finally, if there's no clever trick then what is the right way to change these variables that depend on the current state? 最后,如果没有聪明的窍门,那么根据当前状态更改这些变量的正确方法是什么? Will I need to write a function that sets up each and every one every time the context changes? 我是否需要编写一个函数来设置每次上下文更改的每个函数?

Assuming I'm following this correctly, bar is a global variable and func_to_get_foo isn't something you can manually fold. 假设我正确地遵循了这一点, bar是一个全局变量, func_to_get_foo不是可以手动折叠的东西。 That does indeed make it tough. 确实确实使它变得困难。 In fact, there's no way to do this in portable c code. 实际上,在可移植的c代码中无法做到这一点。 In the old days, we put this stuff early in main() which worked well enough. 在过去,我们将这些东西放在main()前面,效果很好。

With gcc we can now use attribute((constructor)) 使用gcc我们现在可以使用attribute((constructor))

bar_t bar; /* cannot declare this const as this might place it in readonly memory */
attribute((constructor))
static void init_bar(){
    bar.baz = func_to_get_foo();
}

Be careful; 小心; this only works if state_t state_ctx; 仅在state_t state_ctx; was initialized with a const initializer otherwise this technique is utterly unreliable. 已使用const初始值设定项进行了初始化,否则此技术完全不可靠。 Attribute initializers do run in an order, but it's not the order you want. 属性初始化程序确实按顺序运行,但这不是您想要的顺序。 In the second case we have to lean even farther on gcc 's extensions to replicate c++ 's iostream magic as follows: 在第二种情况下,我们必须进一步依靠gcc的扩展来复制c++iostream魔术,如下所示:

attribute((constructor))
static void init_bar(){
    init_state();
    bar.baz = func_to_get_foo();
}

/* ... */

state_t state;
static char state_initialized;
attribute((constructor))
void init_state()
{
    if (state_initialized) return;
    state_initialized = 1;
    /* do whatever to fill out state */
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM