编程实用小组件整理

1. 打印宏名

打印枚举时,一般只能打印对应的整型值,以下两种方法可以打印枚举对应的字符串

#include<stdio.h>
enum color
{
        red,
        green,
        black,
        yellow
};

#define ENUMNAME(n) case n: return #n
const char* print_enum_name(int n)
{
        switch(n) {
                ENUMNAME(red);
                ENUMNAME(green);
                ENUMNAME(black);
                default: return "unknow enum";
        }
}

int main(void)
{
        printf("%s\n",print_enum_name(red));
        printf("%s\n",print_enum_name(green));
        printf("%s\n",print_enum_name(black));
        printf("%s\n",print_enum_name(yellow));

}

代码地址:
https://github.com/lupingguang/c_test/tree/master/enum_name_print
tips: red -> ENUMNAME(red);字符串快速转可借助sed

2. 通用接口

在制作so文件时,对使用者开放的接口一般都是固定的,若需要新添加接口,就必须同步修改所有该库的使用者,否则使用者与so不匹配时,编译都无法通过(在so提供的头文件中添加接口,也不会编译通过,因为链接时,链接器需要定位到所有应用程序使用到的接口,以便运行时,根据接口符号表分配运行地址)。
可以在so中导出一个形参为字符串的接口,字符串代表实际调用的函数,这样使用者在调用某新添加接口时,只需要传递该接口的字符名称,so内部自行遍历一个函数指针结构体来判断是否有该接口,即使没有,也不会引起其它问题,仅仅返回代表调用失败的返回值即可。

//common.h
#ifndef MYSTATICLIB
#define MYSTATICLIB

typedef int (*FuncApi)(void *);
struct CommonApiInfo
{
        FuncApi    FuncApiPtr;
        const char *FuncApiStrName;
        int        FuncApiNR;
};

int Common_call_Interface(char *name, void *InOutParams);

#endif
//common.c
#include <stdio.h>
#include "my_shared_lib.h"
#include <string.h>
static int NewFuncApi(void *InOutParams)
{
        printf("[so]use first params as char %c\n", ((char *)InOutParams)[0] );
        printf("[so]use first params as int %d\n", ((int *)InOutParams)[1] );

        ((int *)InOutParams)[2] = 55;
        return 0;
}
struct CommonApiInfo  CommonApiArray[MAX_COMMON_API_NR] =
{
        {NewFuncApi, "NewFuncApi", 1}
        //add new api...
};

int Common_call_Interface(char *name, void *InOutParams)
{
        unsigned int u32EntryIndex = 0;
        int          ret = 0;
        for(u32EntryIndex  = 0; u32EntryIndex <MAX_COMMON_API_NR; u32EntryIndex ++)
        {
                //
                if(CommonApiArray[u32EntryIndex].FuncApiNR == 0)
                {
                        printf("Func: %s, isnt found in CommonApiArray,force return \n", name);
                        return -1;
                }
                if(!strcmp(name, CommonApiArray[u32EntryIndex].FuncApiStrName))
                {
                        if(NULL != CommonApiArray[u32EntryIndex].FuncApiPtr && NULL != InOutParams)
                        {
                                ret = CommonApiArray[u32EntryIndex].FuncApiPtr(InOutParams);
                                printf("Func: %s, found in CommonApiArray,FuncApiNR=%d\n", name, u32EntryIndex + 1);
                                return ret;
                        }
                        else
                        {
                                return -1;
                        }
                }
        }
}

#include <stdio.h>
#include "my_shared_lib/my_shared_lib.h"
int main(void)
{
        int Params[3] ={100,1,0};
        Common_call_Interface("NewFuncApi", (void *)Params);
        printf("[app]get param from so:%d\n",Params[2]);
        return 0;
}

3 bin文件存储数据

1.原理
C库函数读写二进制文件,将文件使用少量格式分段存储用户格式化数据
例如从第5个字节[字节编号0开始]开始存储一个结构体,结构体中包含5个int型成员,第1个为校验码[9],第2个到第5个为有效数据[4,3,2,1]
实际会在第5字节处存放一个起始地址[本例中为5,也叫做mark],然后偏移10个字节后开始存储[10个字节用来存放起始地址],
最终在bin文件中的分布如下[hexdump -C bin_file即可查看]:

00000000  00 00 00 00 00 05 00 00  00 00 00 00 00 00 00 09  |................|
00000010  00 00 00 04 00 00 00 03  00 00 00 02 00 00 00 01  |................|

2.使用步骤
每次运行时需首先检查bin文件有效性,方法是读取指定位置的起始地址,一般读取位置地址 = 存放的地址即为校验正确
校验失败的情况有:
1、第一次运行,还未创建bin文件
2、用户修改了存储起始地址
3、bin文件损坏

如果校验失败,都会remove掉这个bin文件[第一次运行时的校验失败除外]
后面类实例化时会重新新建该bin文件
新建该文件后,必须执行一次打mark动作,这样下次运行时才能校验通过

3.运行程序时 跟任意一个参数就会触发写读操作,验证bin文件是否可正常使用
注意:写数据的实际起始地址是用户制定地址+10字节的偏移,这样可保证每次更新数据不会冲掉mark,导致下次运行校验失败,再新建文件
+10字节偏移逻辑在源文件的read与save中已写死,可根据需要调整

地址:https://github.com/lupingguang/c_test/tree/master/bin_rw

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值