如何在C中创建派生结构属性
在Python中,例如可以使用如何在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
@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语言中实现这一点的最佳方法是什么(速度是最重要的)。我在下面添加了一些我尝试过的方法,但不确定它们是否会在更大的代码库中产生影响。详情如下:
#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];
}