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

标签 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_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 语言中实现这一目标的最佳方法是什么(其中速度是最重要的)。我在下面添加了一些我尝试过的方法,但不确定它们是否会对更大的代码库产生影响。它们如下:

  1. 每次只需写出整个表达式。 优点:没有意外的影响,没有代码/速度损失。 缺点:代码丑陋,需要很长时间编写。
  2. 使用获取函数。 优点:代码更容易阅读。 缺点:代码效率低(慢于 1)。
  3. 定义宏。 优点:没有代码/速度损失。代码写起来很快。 缺点:以后可能会产生影响,代码不太容易理解。

示例程序如下

#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;
}

最佳答案

通过静态内联函数,您可以充分利用两个领域(函数和宏)的可读性和性能。

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

也就是说,您的 get_state 不满足(我的)静态内联函数的要求,但如果您只想让函数只获取 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 State {...};static inline 函数通常会进入 header .h 文件。

此外,我会通过这种方式改进您的 get_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 文件中,尽管 enum Properties 应该出现在 header 中文件,以便该函数的用户可以使用它。

编辑:使用数组添加高性能版本

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

main.c

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

当然,您可以将类型更改为您想要的任何类型。我使用了 uint_fast8_t,因为您的数据可以容纳其中,而且它是任何系统上最快的类型。

关于c - 如何在 C 中创建派生结构属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54957598/

相关文章:

c - 代码没有输出,但正在运行。 [C]

iphone - 为 iPad 和 iPhone 运行时创建不同的@properties

c++ - 如何选择二维数组中的另一列?

c++ - GNU c 和 c++ 中 SIMD 函数的问题

java - C 在函数中修改值的最佳方式

c - 冒泡排序动态结构

c++ - 通过 UDP 套接字发送结构 memcopy C++

c# - 为什么 .NET 值类型是密封的?

java - Spring Boot 配置属性未设置

ExtJS 属性网格可调整大小的列?