仅使用一个函数更新全局 C 结构而不传递整个数据结构

Update global C struct using only one function without passing whole data structure

我正在开发一个数据库访问层来存储软件子系统的数据。数据库接口有两个函数,database_get()database_set()。它们有两个参数,第一个是标识软件组件的 ID,第二个参数是一个 typedef 结构,用于保存该软件组件的新设置。然后我有:

#define COMPONENT1_ID 7
typedef struct
{
    int member1;
    char member2;
    char member3;

}   COMPONENT1_STRUCT_T ;

我可以调用 database_set(COMPONENT1_ID, (void *) &new_struct)database_get(COMPONENT1_ID, (void *) &new_struct) 函数存储和检索持久数据。对于使用此数据库存储来自任何其他软件子系统的数据,它的工作方式相同。

现在我正在开发 APIs 来管理这个软件子系统。此 API 由用户界面使用。软件子系统的 API 负责执行组件背后的所有逻辑,并调用数据库以使其数据持久化。我为 API 开发了一个函数,它执行操作并最终调用这样的函数:

int save_new_member1_db(int member1);
{ 
    COMPONENT1_STRUCT_T new_setting;

    database_get(COMPONENT1_ID, (void *)&new_setting);
    new_setting.member1 = member1;
    database_set(COMPONENT1_ID, (void *)&new_setting); 
}

我想知道我是否可以避免创建一个新函数来更新数据库中的每个成员数据。

此外,如果这意味着子系统 API 被缩减为一个函数,我也不希望一个大函数占用整个结构或结构的所有成员。子系统可以是 LED 显示屏,它的 API 可以是不同的方法来做一件事情,例如 update_led_display_color(const LED_DISPLAY_COLOR new color), update_led_display_font(const LED_DISPLAY_FONT cur_font), get_led_display_font(LED_DISPLAY_FONT *cur_font) 。 ..

您将需要在表示成员的符号常量与设置该成员所需的信息之间进行某种映射。您可以为每个成员使用类似 "COMPONENT1_ID" 的内容,并为每个成员提供一个大小+偏移量信息数组,如下所示:

#include <stdio.h>
#include <stddef.h>
#include <string.h>

// in header file (or wherever so that it is visible to
// the definition of "Test_save_member" and not a part of
// the subsystem API)
#define TEST_ID 7 


// in a c file (in your database implementation, I assume)
typedef struct
{
    int mem1;
    char mem2;
    char mem3;
} Test;

// for sure in header file exposed in your subsystem API
typedef enum
{
    MEM1,
    MEM2,
    MEM3,
    NUM_MEMBERS
} TestMember;

// in c file (in your database implementation, I assume again)

typedef struct
{
    size_t offset;
    size_t size;
} MemberInfo;

static MemberInfo member_info[NUM_MEMBERS] =
{
    { offsetof(Test, mem1), sizeof(int) },
    { offsetof(Test, mem2), sizeof(char) },
    { offsetof(Test, mem3), sizeof(char) }
};

// also a part of your subsystem API
int Test_save_member(TestMember member, void* value)
{
    if (!value || member < 0 || member >= NUM_MEMBERS))
        return 0;

    Test new_setting;
    database_get(TEST_ID, (void *)&new_setting);
    MemberInfo info = member_info[member];
    memcpy((char*)(&new_setting) + info.offset, value, info.size);
    database_set(TEST_ID, (void *)&new_setting);
    return 1;
}

// subsystem API usage
int main(void)
{
    int new_mem1 = 5;
    Test_save_member(MEM1, &new_mem1);
    return 0;
}

根据您是否要编辑数据库功能、要处理的耦合量等,这可能会发生巨大变化;但是,我不认为鉴于您提到的限制,您可以在没有某种类型的映射的情况下逃脱。

这个特定的实现将不允许传递文字,但这应该不是太大的问题(处理或解决)。