c - 如何在 C 中创建派生结构属性
问题描述
在 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)。
- 定义宏。优点:没有代码/速度损失。代码快写。缺点:以后可能会产生影响,代码不太容易遵循。
示例程序如下
#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;
}
解决方案
您可以通过函数获得两全其美(函数和宏)的可读性和性能static inline
。
您通常不会使用它,但如果您知道编译器会优化其代码,那么使用它就可以了。我使用的通常规则是 3 行或更少的代码,并且该函数应该需要额外的性能。
也就是说,您get_state
不符合(我的)对static inline
函数的要求,但如果您只希望函数仅获取 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
函数通常会放在头.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
应该放在一个头文件中,以便函数的用户可以使用它。
编辑:使用数组添加高性能版本
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
,因为您的数据可以放入其中,并且它是任何系统上最快的类型。
推荐阅读
- node.js - TypeError:无法读取nodejs中未定义的属性“发送”
- javascript - 脚本运行后执行正文中的 Html 代码
- c# - 如何访问 UiPath 中使用的 .NET 代码?
- php - 在 XAMPP 中的服务器上找不到请求的 URL
- mongodb - 相同的案例类不同的验证
- python - 标准输入关闭时 Python PDB 退出
- google-analytics - 谷歌分析回滚可能吗?
- android - Android资源编译失败(缓存文件错误)
- python - 安装了 CUDA 9.2 时无法导入 tensorflow 1.10
- android - 如何在 Activity 中使用 Butterknife 和 onClickListener?