You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言中简化increase_log_info函数,实现无判断动态数据类型更新

技术问询

需求背景:需要实现一个LOG参数更新接口,传入参数索引和待增加值,将值累加到对应参数上,要求实现简洁,无复杂判断。

我的实现思路:创建映射表,记录每个参数在T_LOG_INFO结构体中的偏移量和数据类型。调用接口时,根据参数索引获取参数地址,强制转换为对应类型后执行加法操作。

现存问题:当前实现的increase_log_info函数包含较多if...else条件判断,过于复杂,希望简化该函数,实现参数类型的直接映射,而非通过条件判断。

注意事项:

  • T_LOG_INFO结构体定义不可修改;
  • 外部提供的LOG_INFO_INCREASE更新接口不可修改;
  • 其他代码可调整。

相关代码:

#pragma once

/********************************can not be change, begin**********************************/
/* T_LOG_INFO is data structure definition and cannot be changed. */
typedef struct
{
    unsigned short           tx_num;
    unsigned int             tx_bytes;
    unsigned short           rx_num;
    unsigned int             rx_bytes;
    unsigned char            discard_num;
    unsigned int             discard_bytes;
    // There are many parameters behind, not listed
}T_LOG_INFO;

T_LOG_INFO g_log_info;

/* This macro is called very frequently, and efficiency needs to be considered.
** LOG_INFO_INCREASE is an update parameter interface provided externally and cannot be changed. */
//#define LOG_INFO_INCREASE(para_idx, inc_val)
/********************************can not be change, end**********************************/

/********************************an alternative, begin**********************************/
enum
{
    LOG_PARA_IDX_TX_NUM,
    LOG_PARA_IDX_TX_BYTES,
    LOG_PARA_IDX_RX_NUM,
    LOG_PARA_IDX_RX_BYTES,
    LOG_PARA_IDX_DISCARD_NUM,
    LOG_PARA_IDX_DISCARD_BYTES,
    LOG_PARA_IDX_MAX
};

enum
{
    DATA_TYPE_U8,
    DATA_TYPE_U16,
    DATA_TYPE_U32
};

typedef struct
{
    /* Indicates the offset of this parameter in the structure. */
    unsigned char            offset;
    /* Indicates the data type of the parameter. */
    unsigned char            data_type;
}T_PARA_MAPPING;

/* This table can also be calculated during system initialization. */
T_PARA_MAPPING g_para_mapping_table[LOG_PARA_IDX_MAX] =
{
    {0, DATA_TYPE_U16},  // LOG_PARA_IDX_TX_NUM
    {4, DATA_TYPE_U32},  // LOG_PARA_IDX_TX_BYTES
    {8, DATA_TYPE_U16},  // LOG_PARA_IDX_RX_NUM
    {12, DATA_TYPE_U32}, // LOG_PARA_IDX_RX_BYTES
    {16, DATA_TYPE_U8},  // LOG_PARA_IDX_DISCARD_NUM
    {20, DATA_TYPE_U32}  // LOG_PARA_IDX_DISCARD_BYTES
};

/* How to simplify the function??? especially to remove the judgment. */
static inline void increase_log_info(unsigned int para_idx, unsigned inc_val)
{
    unsigned int data_type = g_para_mapping_table[para_idx].data_type;

    /* Get the parameter address and cast it to the corresponding type pointer before adding. */
    if (data_type == DATA_TYPE_U8)
    {
        *((unsigned char*)(((unsigned char*)&g_log_info) + g_para_mapping_table[para_idx].offset)) += inc_val;
    }
    else if (data_type == DATA_TYPE_U16)
    {
        *((unsigned short*)(((unsigned char*)&g_log_info) + g_para_mapping_table[para_idx].offset)) += inc_val;
    }
    else
    {
        *((unsigned int*)(((unsigned char*)&g_log_info) + g_para_mapping_table[para_idx].offset)) += inc_val;
    }
}

/* This macro is called very frequently, and efficiency needs to be considered. */
#define LOG_INFO_INCREASE(para_idx, inc_val) increase_log_info(para_idx, inc_val)
/********************************an alternative, end**********************************/

/********************************test case, begin**********************************/
void increase_log_info_test()
{
    LOG_INFO_INCREASE(LOG_PARA_IDX_TX_NUM, 1);
    LOG_INFO_INCREASE(LOG_PARA_IDX_TX_NUM, 2);
    LOG_INFO_INCREASE(LOG_PARA_IDX_TX_NUM, 3);

    LOG_INFO_INCREASE(LOG_PARA_IDX_RX_BYTES, 10);
    LOG_INFO_INCREASE(LOG_PARA_IDX_RX_BYTES, 20);
    LOG_INFO_INCREASE(LOG_PARA_IDX_RX_BYTES, 30);
}
/********************************test case, end**********************************/

解决方案

要消除increase_log_info里的if...else判断,有两种高效且简洁的实现方式,均符合你的约束条件:

方案1:函数指针映射表

修改映射表结构,直接绑定对应类型的累加函数,运行时无需条件判断,直接调用对应函数:

// 提前定义各类型的累加函数
static inline void inc_u8(unsigned char* ptr, unsigned val) { *ptr += val; }
static inline void inc_u16(unsigned short* ptr, unsigned val) { *ptr += val; }
static inline void inc_u32(unsigned int* ptr, unsigned val) { *ptr += val; }

// 重新定义映射表,用函数指针替代类型枚举
typedef void (*IncFunc)(void*, unsigned);
typedef struct
{
    unsigned char offset;
    IncFunc inc_func;
}T_PARA_MAPPING;

// 初始化映射表,用offsetof宏自动计算偏移,避免手动出错
T_PARA_MAPPING g_para_mapping_table[LOG_PARA_IDX_MAX] =
{
    {offsetof(T_LOG_INFO, tx_num), (IncFunc)inc_u16},
    {offsetof(T_LOG_INFO, tx_bytes), (IncFunc)inc_u32},
    {offsetof(T_LOG_INFO, rx_num), (IncFunc)inc_u16},
    {offsetof(T_LOG_INFO, rx_bytes), (IncFunc)inc_u32},
    {offsetof(T_LOG_INFO, discard_num), (IncFunc)inc_u8},
    {offsetof(T_LOG_INFO, discard_bytes), (IncFunc)inc_u32}
};

// 简化后的累加函数,无任何条件判断
static inline void increase_log_info(unsigned int para_idx, unsigned inc_val)
{
    T_PARA_MAPPING* map = &g_para_mapping_table[para_idx];
    map->inc_func((unsigned char*)&g_log_info + map->offset, inc_val);
}

这种方式把类型判断转移到初始化阶段,运行时仅需一次指针查找和函数调用,效率稳定,同时避免了手动维护偏移量的错误。

方案2:编译期宏优化(零运行时开销)

如果调用LOG_INFO_INCREASE时的参数索引是编译期常量(比如测试用例里的枚举值),可以用宏在编译期直接生成对应类型的累加代码,完全消除运行时判断:

// 定义通用分支生成宏,简化代码重复
#define _LOG_INFO_INC_CASE(idx, member, type) \
    case idx: *((type*)((unsigned char*)&g_log_info + offsetof(T_LOG_INFO, member))) += val; break

// 重构LOG_INFO_INCREASE宏,保持原有接口不变
#define LOG_INFO_INCREASE(para_idx, inc_val) do { \
    unsigned val = inc_val; \
    switch(para_idx) { \
        _LOG_INFO_INC_CASE(LOG_PARA_IDX_TX_NUM, tx_num, unsigned short); \
        _LOG_INFO_INC_CASE(LOG_PARA_IDX_TX_BYTES, tx_bytes, unsigned int); \
        _LOG_INFO_INC_CASE(LOG_PARA_IDX_RX_NUM, rx_num, unsigned short); \
        _LOG_INFO_INC_CASE(LOG_PARA_IDX_RX_BYTES, rx_bytes, unsigned int); \
        _LOG_INFO_INC_CASE(LOG_PARA_IDX_DISCARD_NUM, discard_num, unsigned char); \
        _LOG_INFO_INC_CASE(LOG_PARA_IDX_DISCARD_BYTES, discard_bytes, unsigned int); \
    } \
} while(0)

编译器会识别para_idx为常量,自动将switch分支优化为直接的内存访问和加法指令,没有任何运行时判断开销,特别适合接口被频繁调用的场景。

两种方案均满足要求:无复杂条件判断,实现简洁,且不修改T_LOG_INFO和LOG_INFO_INCREASE的对外接口。如果参数索引可能是运行时变量,选方案1;如果索引都是编译期常量,方案2性能最优。

内容的提问来源于stack exchange,提问作者nn huang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 12:31:26