gpt4 book ai didi

c - 函数内部变量的变量类型

转载 作者:行者123 更新时间:2023-11-30 14:34:50 24 4
gpt4 key购买 nike

我有不同类型的结构,它们将被传递给一个对其执行相同任务的函数。

int menu_parameter_arrow_print(game_setting_identifier* identifier, controller_direction direction, uint8_t position)
{
if((position > setting->alternatives_number) || position < 0)
{
#ifdef OLED_PRINT_DEBUG_ENABLE
OLED_debug_print("Out of bounds");
#endif
return RETURN_VALUE_FAILURE;
}
else
{

switch ((int)*identifier)
{
case ((int) GAME_SETTING_ANALOG):
game_setting_analog* setting = (game_setting_analog*)&identifier;
case ((int) GAME_SETTING_TOGGLE):
game_setting_toggle* setting = (game_setting_toggle*)&identifier;
case ((int) GAME_SETTING_VALUE):
game_setting_value* setting = (game_setting_value*)&identifier;
}

该函数给出了冲突的类型错误

对结构体执行的操作是相同的,但结构体包含不同类型的成员:

struct game_setting_analog
{
//Identifier for the game-setting type:
game_setting_identifier identifier;
//Alternatives:
char* alternatives[4];
};
typedef struct game_setting_value game_setting_value;

struct game_setting_value
{
game_setting_identifier identifier;
uint8_t* alternatives[6];
uint8_t alternatives_number;
};
typedef struct game_setting_toggle game_setting_toggle;

struct game_setting_toggle
{
//Identifier for the game-setting type:
game_setting_identifier identifier;
toggle_state* alternatives[2];
};
typedef struct game_setting_difficulty game_setting_difficulty;

struct game_setting_difficulty
{
game_setting_identifier identifier;
char* alternatives[3];
};

操作将对结构的“替代”成员执行,即使这些成员具有不同的类型。

有没有一种解决方案可以做到这一点,而不必为每个标识符使用一个 if 语句?

编辑:通过修改 switch-case,我能够编译初始化。然而,开关范围内的变量对函数的其余部分不可见

int menu_print_parameter_line(game_setting_identifier* identifier, controller* C, uint8_t position)
{
uint8_t next_position = position;
controller_direction previous_direction = C->joystick.generalDirection;

if ((identifier == NULL) || (C == NULL) || (position == NULL))
{
return -1;
}

switch((int) identifier)
{
case ((int) GAME_SETTING_ANALOG):
{
game_setting_analog* setting = (game_setting_analog*)identifier;
uint8_t alternatives_number = 4;
}
break;
case ((int) GAME_SETTING_TOGGLE):
{
game_setting_toggle* setting = (game_setting_toggle*)identifier;
uint8_t alternatives_number = 2;
}
break;
case ((int) GAME_SETTING_VALUE):
{
game_setting_value* setting = (game_setting_value*)identifier;
uint8_t alternatives_number = setting->alternatives_number;
}
break;
default:
{
return -1;
}
break;
}

#ifdef MENU_PARAMETER_ASSIGNMENT_DEBUG
OLED_debug_print("before switch-case");
#endif
switch (previous_direction)
{
case LEFT:
next_position -= 1;
if(next_position <= 0)
{
next_position = alternatives_number;
}

最佳答案

我个人不喜欢依赖于结构的第一个成员的继承模型,就像 BSD 套接字库正在使用的那样。基本上,您只是尝试在 C 中从 c++ 实现 std::variant

Is there a solution to doing this without having to use one if-statement for each identifier?

接口(interface)的面向对象概念非常好用,我相信在这种情况下也适用。编写它需要一些 C 规则,但它的工作方式就像一个魅力,您可以在这里寻找它。

我复制了您的定义,并从中删除了 typedef,因为我不喜欢它们:

struct game_setting_analog {
char* alternatives[4];
};

struct game_setting_value {
uint8_t* alternatives[6];
uint8_t alternatives_number;
};

struct game_setting_toggle {
toggle_state* alternatives[2];
};

struct game_setting_difficulty {
char* alternatives[3];
};

让我们首先使用允许获取替代编号的函数指针来实现接口(interface)抽象:

// forward definition
struct game_setting_s;

// the virtual table for game_settings
struct game_setting_vtable_s {
uint8_t (*get_alternatives_number)(struct game_setting_s *t);
// TODO: add other members, constructor, copy constructor, destructor, etc.
};

// represents any game_setting
// exposes a public interface to access and manipulate a game_setting
struct game_setting_s {
// the vtable is const, so it can save RAM
const struct game_setting_vtable_s *v;
// this is a pointer to private settings data
void *data;
};

// accessor for less (or more ;) typing
static inline
uint8_t game_setting_get_alternatives_number(struct game_setting_s *t) {
// alternative you could pass t->data to the function, I pass it all
// so that functions can modify the t->data member
// and also so that advanced functions usages can use like container_of macros
return t->v.get_alternatives_number(t);
}

然后您需要为每种类型提供虚拟表。这些定义可以是不同的类型,因此您可以为每个类型拥有一个单独的 .c/.h 文件对,仅公开公共(public)接口(interface)。

// game_setting_analog --------------------

static
uint8_t game_setting_analog_get_altenatives_number(struct game_setting_s *t)
{
return 4;
}

const struct game_setting_vtable_s game_setting_analog_vtable = {
.get_alternatives_number = game_setting_analog_get_altenatives_number,
};

// game_setting_toggle --------------------

static
uint8_t game_setting_toggle_get_altenatives_number(struct game_setting_s *t) {
struct game_setting_toggle *data = t->data;
return data->alternatives_number;
}

const struct game_toggle_vtable_s game_setting_toggle_vtable = {
.get_alternatives_number = game_setting_toggle_get_altenatives_number,
};

// and so on...

那么你的函数只需要界面并且非常清晰,没有任何 switch case:

int some_function_that_needs_to_know_which_setting_is_passed(struct game_setting_s *s) {
int number_of_alternatives = game_setting_get_alternatives_number(s);
}

记住正确构造接口(interface)对象并观察谁拥有该对象的内存。让我们构建一个切换和调用函数:

struct game_settting_toggle memory;

// your function to initialize the toggle
game_setting_toggle_intialize(&memory);

// the interface is constructed with the proper vtable
// and a pointer to proper memory region with the data
struct game_setting_s any_setting = {
.vtable = game_setting_toggle_vtable,
.data = &memory,
};

// the initailize function could be in interface too
// so you would just call game_setting_initialize(&any_setting);
// with usage of dynamic allocation, you can just ex.
// struct game_setting_s *any_setting = game_setting_new_toggle();
// and write proper object-oriented factories

// finally call our function.
some_function_that_needs_to_know_which_setting_is_passed(&any_setting);

关于c - 函数内部变量的变量类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58818510/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com