如何在C中创建派生结构属性

如何在C中创建派生结构属性,c,struct,properties,C,Struct,Properties,在Python中,例如可以使用@property装饰器从类创建派生属性 class State(): def __init__(self, fav_num_monday, fav_num_not_monday, is_monday): self.fav_num_monday = fav_num_monday self.fav_num_not_monday = fav_num_not_monday self.is_monday = is_mo

在Python中,例如可以使用
@property
装饰器从类创建派生属性

class State():
    def __init__(self, fav_num_monday, fav_num_not_monday, is_monday):
        self.fav_num_monday = fav_num_monday
        self.fav_num_not_monday = fav_num_not_monday
        self.is_monday = is_monday

    @property
    def fav_num(self):
        return self.is_monday * self.fav_num_monday + \
            (1 - self.is_monday) * self.fav_num_not_monday

state = State(12, 5, 0)
print("Current favourite number: %d" % state.fav_num)
我的问题是,在C语言中实现这一点的最佳方法是什么(速度是最重要的)。我在下面添加了一些我尝试过的方法,但不确定它们是否会在更大的代码库中产生影响。详情如下:

  • 每次只需写出整个表达式。 优点:没有意外的反应,没有代码/速度惩罚。 缺点:难看的代码,需要很长时间来编写
  • 使用get函数。 优点:代码更容易阅读。 缺点:代码效率低(比1慢)
  • 定义宏。 优点:无代码/速度惩罚。快速编写代码。 缺点:以后可能会产生影响,代码不容易理解 下面是示例程序

    #include <stdio.h>
    #include <string.h>
    
    #define state_fav_num  state.is_monday * state.fav_num_monday + (1 - state.is_monday) * state.fav_num_not_monday
    
    struct State {
        int fav_num_monday;
        int fav_num_not_monday;
        int is_monday;
    };
    
    int get_state(struct State *state, char *property) {
        // Returns value of the property in state. 
        // Allows us to create derived properties also.
        if (!strncmp(property, "fav_num_monday", 14)) {
            return state->fav_num_monday;
        } else if (!strncmp(property, "fav_num_not_monday", 18)) {
            return state->fav_num_not_monday;
        } else if (!strncmp(property, "is_monday", 9)) {
            return state->is_monday;
        } else if (!strncmp(property, "fav_num", 7)) {
            return state->is_monday * state->fav_num_monday +
                (1 - state->is_monday) * state->fav_num_not_monday;
        }
    }
    
    int main() {
        // Set the state.
        struct State state;
        state.fav_num_monday = 12;
        state.fav_num_not_monday = 5;
        state.is_monday = 1;
    
        // Print favourite number in different ways.
        printf("\n1) Current favourite number is %d.",
            state.is_monday * state.fav_num_monday +
            (1 - state.is_monday) * state.fav_num_not_monday);
    
        printf("\n2) Current favourite number is %d.",
            get_state(&state, "fav_num"));
    
        printf("\n3) Current favourite number is %d.",
            state_fav_num);
    
        printf("\n");
    
        return 0;
    }
    
    #包括
    #包括
    #定义state\u fav\u num state.is\u monday*state.fav\u num\u monday+(1-state.is\u monday)*state.fav\u num\u not\u monday
    结构状态{
    国际货币基金组织星期一;
    星期一不上班;
    int是星期一;
    };
    int get_state(结构状态*状态,字符*属性){
    //返回状态中属性的值。
    //还允许我们创建派生属性。
    如果(!strncmp(属性,“fav_num_monday”,14)){
    返回状态->fav_num_周一;
    }否则,如果(!strncmp(属性,“fav_num_not_monday”,18)){
    返回状态->fav_num_not_monday;
    }否则如果(!strncmp(属性“is_monday”,9)){
    返回状态->是星期一;
    }否则如果(!strncmp(属性,“fav_num”,7)){
    返回状态->是星期一*状态->最早的星期一+
    (1-州->星期一是)*州->星期一不是星期一;
    }
    }
    int main(){
    //设定状态。
    结构状态;
    state.fav_num_monday=12;
    state.fav_num_not_monday=5;
    state.is_monday=1;
    //以不同的方式打印喜爱的号码。
    printf(“\n1)当前最喜爱的号码是%d.”,
    state.is_周一*state.fav_num_周一+
    (1-州是星期一)*州是星期一不是星期一);
    printf(“\n2)当前最喜爱的号码是%d.”,
    获取状态(状态“fav_num”);
    printf(“\n3)当前最喜爱的号码是%d.”,
    州(数量);
    printf(“\n”);
    返回0;
    }
    
    使用
    静态内联
    函数,您可以在可读性和性能方面充分利用这两个方面(函数和宏)

    您通常不会使用它,但是如果您知道编译器将要优化其代码,那么使用它是可以的。我通常使用的规则是3行或更少的代码,函数应该需要额外的性能

    也就是说,您的
    get_state
    不满足
    静态内联
    函数的(my)要求,但是如果您只希望函数只获取fav_num,那么这是有意义的:

    struct State {
        int     fav_num_monday;
        int     fav_num_not_monday;
        bool    is_monday;
    };
    
    
    static inline   int get_fav_num(const struct State *state)
    {
    
        if (state->is_monday)
            return  state->fav_num_monday;
        else
            return  state->fav_num_not_monday;
    }
    
    
    int main(void)
    {
        struct State state;
        int fav_num;
    
        state   = (struct State){
            .fav_num_monday     = 12;
            .fav_num_not_monday = 5;
            .is_monday          = 1;
        };
    
        // Print favourite number in different ways.
        printf("\n");
        if (state.is_monday)
            fav_num = state->fav_num_monday;
        else
            fav_num = state->fav_num_not_monday;
        printf("1) Current favourite number is %d.\n", fav_num);
    
        fav_num = get_fav_num(&state);
        printf("4) Current favourite number is %d.\n", fav_num);
    
        return 0;
    }
    
    免责声明:此代码需要C99或更高版本

    虽然这里的代码都在一起,
    struct状态{…}
    静态内联
    函数通常位于头文件
    .h

    另外,我将通过以下方式改进您的
    get\u state
    功能:

    enum Properties {
        FAV_NUM_MONDAY,
        FAV_NUM_NOT_MONDAY,
        IS_MONDAY,
        FAV_NUM
    };
    
    int get_state(const struct State *state, int property)
    {
    
        switch (property) {
        case FAV_NUM_MONDAY:
            return  state->fav_num_monday;
        case FAV_NUM_NOT_MONDAY:
            return  state->fav_num_not_monday;
        case IS_MONDAY:
            return  state->is_monday;
        case FAV_NUM:
            return  get_fav_num(state);
        default:
            return -1;  /* Error */
        }
    }
    
    此函数将是一个常用的
    extern
    函数,并将放在
    .c
    文件中,尽管
    枚举属性应放在头文件中,以便该函数的用户可以使用它

    编辑:使用阵列添加高性能版本

    state.h

    #include <stdint.h>
    
    enum    State_Properties {
        FAV_NUM_MONDAY,
        FAV_NUM_NOT_MONDAY,
        IS_MONDAY,
        STATE_PROPERTIES
    };
    
    
    static inline
    uint_fast8_t get_fav_num(const uint_fast8_t *restrict (state[STATE_PROPERTIES]))
    {
    
        if ((*state)[IS_MONDAY])
            return  (*state)[FAV_NUM_MONDAY];
        else
            return  (*state)[FAV_NUM_NOT_MONDAY];
    }
    

    当然,您可以将类型更改为任何您想要的类型。我使用了
    uint\u fast8\u t
    ,因为您的数据可以放入其中,而且它是任何系统中最快的类型。

    您不是在试图将面向对象的编程概念硬塞进一种本质上不面向对象的语言,是吗?你考虑C++了吗?为什么使用数学和<代码> int <代码> s来获得(应该)用(<代码> BoOL <代码> > < <代码> > < < /> > >如果您希望在一行中包含某些内容,您至少可以使用
    ?:您可以为C属性使用定义或枚举,为它们指定每个整数值,并将它们存储在结构中的数组中。然后,您可以使用适当的命名索引来访问属性。return语句应该是
    return self.fav\u num\u monday如果self.is\u monday else self.fav\u num\u not\u monday
    。使用“get函数”。如果编译器可以看到函数定义,它通常可以内联,例如在头中定义
    inline
    。如果编译器内联函数,则选项1和选项2之间不会有性能差异。避免使用宏,因为它充其量与选项1具有相同的效果,最坏的情况下,它不考虑范围,并且具有意外的效果。另外,让代码正常工作并保持清晰。如果测试/分析提供了需要的证据,则只需担心性能。像你一样,过早地担心性能被称为“过早优化”,这是有原因的。我只想补充一点,如果所有的
    struct
    类型都相同,那么使用数组(性能)可能会更好,这样你甚至不需要函数来访问它的元素,因为可以使用
    enum
    来命名其位置。我认为这是最好的方法。正如编译时所知,我认为一个好的编译器会避免在每次调用
    get\u state
    时进行线性搜索以查找匹配属性,这是对的吗。如果不是,对于许多属性,这可能变得无效。如果
    get\u state
    与调用者在同一个.c文件中,并且
    属性在编译时是已知的,那么它将直接内联(复制)只要
    state->whatever而不是函数调用。如果编译时
    属性
    未知,则无法进行优化。如果编译时知道
    属性
    ,但调用方位于另一个文件中,我认为它将无法执行
    #include <inttypes.h>
    
    #include "state.h"
    
    int main(void)
    {
        uint_fast8_t    state[STATE_PROPERTIES];
        uint_fast8_t    fav_num;
        uint_fast8_t    fav_num_monday;
    
        state   = (uint_fast8_t [STATE_PROPERTIES]){
            [FAV_NUM_MONDAY]        = 12;
            [FAV_NUM_NOT_MONDAY]    = 5;
            [IS_MONDAY]             = true;
        };
    
        // Print favourite number in different ways.
        fav_num = get_fav_num(&state);
        printf("5) Current favourite number is %"PRIuFAST8".\n", fav_num);
    
        // Example of how to retrieve any property:
        fav_num_monday  = state[FAV_NUM_MONDAY];
    }