C语言结构体数组初始化
一、使用场景
-
在C编码中,经常需要对结构体数组进行初始化。
使用这种方法,能够使得代码更加的清晰,易读。
例如:需要根据返回码,一个status code 做不同的操作。
int process_by_status_code(int status_code) { if(status_code == 180) { //do process 1 } else if(status_code == 183) { //do process 2 } else if(status_code == 200) { //do process 3 } //........此处省略100中情况。 return 0; }
需要注意,使用这种方式编码,随着要处理的情况不断增多,函数必然会越来越大。而且根据《unix编程艺术》中说的,人类大脑更加的善于处理数据,而不是逻辑。
因此可能可以换一种写法:
typedef struct int (*status_code_process_callback)(void *param); typedef struct status_code_process_map { int status_code; status_code_process_callback fn_process; }status_code_process_map; status_code_process_map g_status_code_process_map_list[]= { {180,process_180}, {183,process_183}, {200,process_200}, //.....此处省略N中情况。 }; int process_180(void *param) { //do 180 process return 0; } int process_183(void *param) { //do 183 process return 0; } int process_by_status_code(int status_code) { int i = 0; for(i = 0; i < sizeof(g_status_code_process_map_list)/sizeof(g_status_code_process_map_list[0]); i++) { if(g_status_code_process_map_list[i].fn_process) { return g_status_code_process_map_list[i].fn_process(&status_code); } } return 0; }
这样写,别人看代码,就很容易看到:
从而更快速理解其中的隐藏逻辑。阅读代码效率更高。
二、问题和解决
-
如果在映射表中需要添加参数,怎么办?
typedef struct int (*status_code_process_callback)(void *param); typedef struct status_code_process_map { int status_code; void *param;//需要添加一个参数。 status_code_process_callback fn_process; }status_code_process_map;
那,初始化就不合理了。
对于可能变化成员,或者变化成员顺序的初始化,需要使用这种方法:
status_code_process_map g_status_code_process_map_list[]= { { .status_code = 180, .fn_process = process_180 }, { .status_code = 183, .fn_process = process_183//可以部分初始化 }, { .status_code = 200, .param = NULL, .fn_process = process_200 } //.....此处省略N中情况。 };
使用这种方法,可以对抗成员的添加或者顺序变化。
-
如果某些行不想被初始化,或者不需要被初始化。或者希望提升访问的效率。怎么办?
status_code_process_map g_status_code_process_map_list[]= { {180,process_180}, {183,process_183},//这一行,我认为不需要出现在这里 ,但是又希望其空间是被分配的 {200,process_200}, //.....此处省略N中情况。 };
//这里只能使用status_code进行查找。能否直接调用呢? int process_by_status_code(int status_code) { int i = 0; for(i = 0; i < sizeof(g_status_code_process_map_list)/sizeof(g_status_code_process_map_list[0]); i++) { if(g_status_code_process_map_list[i].fn_process) { return g_status_code_process_map_list[i].fn_process(&status_code); } } return 0; }
可以使用枚举:
enum { E_STATUS_180, E_STATUS_183, E_STATUS_200, //此处省略N种情况 }; status_code_process_map g_status_code_process_map_list[]= { [E_STATUS_180]{180,process_180}, [E_STATUS_183]{183,process_183},//这一行,我认为不需要出现在这里 ,但是又希望其空间是被分配的 [E_STATUS_200]{200,process_200}, //.....此处省略N中情况。 };
使用这种写法,可以省略掉183的初始化,也可以使用g_status_code_process_map_list[E_STATUS_200] 直接访问对应的情况。
三、参考
- 《Unix编程艺术》
- https://www.cnblogs.com/hansjorn/p/4693840.html