如何用函数处理含相同嵌套结构体的不同类型输入?
如何用函数统一操作多个结构体中嵌套的相同子结构体
我有多个结构体,它们内部都嵌套了同一个struct numbers:
struct numbers{ int num_a; int num_b; }; struct var_a{ struct numbers num; // 其他成员变量 }; struct var_b{ struct numbers num; // 其他成员变量 };
我想写一个函数来统一访问这些结构体里的struct numbers(示例操作是给num_a自增1),但不想用宏,也不想依赖struct numbers在父结构体的开头位置。
现有两种方法的局限性
- void指针强制转换法
这种方法要求struct numbers必须是父结构体的第一个成员,否则强制转换会出错:
void foo(void* p_input) { // 原示例代码存在笔误,转换为numbers*后直接访问num_a即可 ((struct numbers*)p_input)->num_a += 1; } int main() { struct var_a a; struct var_b b; foo(&a); foo(&b); return 0; }
- 宏方法
虽然能适配任意位置的struct numbers,但如果实际操作逻辑很复杂,宏的可读性和维护性很差,且typeof是GCC扩展而非标准C语法:
#define foo(type_t, input) \ do{ \ ((type_t*)input)->num.num_a += 1; \ }while(0) int main() { struct var_a a; struct var_b b; foo(struct var_a, &a); foo(struct var_b, &b); return 0; }
我曾尝试用传递类型的方式写函数,但C语言不支持直接传递类型作为参数,以下伪代码不合法:
void foo(void* p_input, type_t input_type) { ((input_type*)p_input)->num.num_a += 1; } int main() { struct var_a a; struct var_b b; foo(&a, typeof(a)); foo(&b, typeof(b)); return 0; }
可行的函数实现方案
方案1:利用offsetof计算成员偏移
借助C标准库的offsetof宏(定义在<stddef.h>中)获取num成员在父结构体中的偏移量,函数根据偏移量找到struct numbers的地址,不需要依赖成员位置:
#include <stddef.h> struct numbers{ int num_a; int num_b; }; struct var_a{ // num可以放在任意位置 int other_var; struct numbers num; }; struct var_b{ struct numbers num; float another_var; }; void foo(void *p_input, size_t num_offset) { // 通过父结构体地址 + 偏移量,得到struct numbers的地址 struct numbers *num_ptr = (struct numbers *)((char *)p_input + num_offset); num_ptr->num_a += 1; // 这里可以添加任意复杂的操作,完全用函数逻辑实现 } int main() { struct var_a a; struct var_b b; // 传递父结构体指针和num成员的偏移量 foo(&a, offsetof(struct var_a, num)); foo(&b, offsetof(struct var_b, num)); return 0; }
方案2:使用函数指针封装成员获取逻辑
为每个父结构体编写一个获取struct numbers*的辅助函数,然后将这个函数指针作为参数传给操作函数,逻辑更清晰,扩展性更好:
struct numbers{ int num_a; int num_b; }; struct var_a{ int other_var; struct numbers num; }; struct var_b{ struct numbers num; float another_var; }; // 定义函数指针类型:输入父结构体指针,返回struct numbers* typedef struct numbers* (*GetNumbersFunc)(void*); // 针对var_a的获取函数 struct numbers* get_var_a_numbers(void *p) { return &((struct var_a*)p)->num; } // 针对var_b的获取函数 struct numbers* get_var_b_numbers(void *p) { return &((struct var_b*)p)->num; } void foo(void *p_input, GetNumbersFunc get_num_ptr) { struct numbers *num_ptr = get_num_ptr(p_input); num_ptr->num_a += 1; // 复杂操作写在这里 } int main() { struct var_a a; struct var_b b; foo(&a, get_var_a_numbers); foo(&b, get_var_b_numbers); return 0; }
这两种方案都是纯函数实现,不需要使用宏,也不依赖struct numbers在父结构体中的位置,完全满足需求。
内容的提问来源于stack exchange,提问作者SoftwareBug
相关产品推荐
相关产品推荐

