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

标签 c struct types avr

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

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/

相关文章:

c - 文件处理 C 程序可以读取的格式

c - windows mingw asterisk '*' 通过 argv[1] 传递给字符串

c - 我正在尝试创建一个交互式 shell

c - C中的这些枚举有什么区别?

postgresql "timestamp without time zone"的 hibernate 映射?

在 C 中组合打印语句

c - 如何在结构中交换数组的结构元素 - C

haskell 错误: Couldn't match expected type `Integer' against inferred type `Int'

斯卡拉拼图 : enforcing that two function arguments are of the same type AND both are a subtype of a given class

c - 在C中实现2个具有相同类型和名称但参数不同的函数