C语言常用库函数
常用string库函数、printf打印文件名行号、sprintf拼接、时间字符串和时间戳互相转换
一、字符串的复制比较用strcpy或strncpy,strcmp(如果用如下函数比较(memcmp)则会出错)
代码如下:
1 #include<stdio.h> 2 #include<string.h> 3 4 #define debug_msg(fmt,...) printf("%s[%d]:"fmt,__FILE__,__LINE__,##__VA_ARGS__) 5 6 #define printf_my(fmt, ...) printf("%s %s %s %s %d:"fmt, __FILE__, __FUNCTION__, __DATE__, __TIME__, __LINE__, ##__VA_ARGS__) 7 8 int main(void) 9 { 10 char str1[10]={"ABCD"}; 11 char str2[100]={"ABCD"}; 12 13 char str3[10]={"ABCD"}; 14 char str4[100]={"ABCD"}; 15 16 int i=0; 17 int ret =0; 18 19 ret=memcmp(str2,str1,sizeof(str2)); 20 21 i = strcmp(str4,str3); 22 23 debug_msg("ret:%d,i:%d\n",ret,i); 24 printf_my("ret:%d,i:%d\n",ret,i); 25 }
三者区别:1、strcpy,strncpy复制字符串时遇到\0会结束,比如abc0def,只能复制到abc。
2、strcpy复制的是整个字符串,而strncpy复制的是字符串的count长度。同理,strcmp比较的是整个字符串,而strncmp比较的是字符串的count长度。
3、memcpy是count个内存地址的复制,包含0,运用于不确定是否是字符串的场合。
同理:memcpy是count个内存地址的比较,因此两个数组大小相差较大时,函数行为不确定。如一所示图片。因此字符串的比较一定要用strcpy函数。
注意:在使用strncpy时,如果to的内存空间小于count长度,则会内存溢出,会导致程序崩溃,设备重启。因此一般需要自己封装一个函数。如下:
1 u8 memcpysafe(char *_dest,const char *_src,size_t _n, size_t _destSizeof) 2 { 3 _destSizeof--; 4 if(_n > _destSizeof) 5 _n = _destSizeof; 6 7 memcpy(_dest,_src,_n); 8 _dest[_n]=0x0;//增加结束符 9 10 debug_msg("数据格式异常");//会将文件名和行号打印出来 11 return 1; 12 }
二、memset
char *buff = NULL;
buff = malloc(In_len+20);
如下:memset在清空malloc申请的内存时,不能使用sizeof(buff)的形式,而是要用申请时的In_len+20,如:memset(buff,0,sizeof(In_len+20));
三、sprintf
如下:可以拼接字符串{"ic_sercret":"adkddke"},如果后面还有数据,就会在数据中间拼接逗号{"ic_sercret":"adkddke","ic_secret_fm":"kalkdajeakal"}
如果没有数据,字符串里就只有一个'{',有符号多余不影响,只要满足需求就行了。
1 savecfg[0]='{'; 2 ret = getKeyValueString(jsonmap2,"secret",tmp_buff,sizeof(tmp_buff)); 3 if(ret>0){ 4 if(strcmp(usrcfg->ic_secret,tmp_buff)!=0){//memcmp函数的第一个数组总是要比第二个数组小,否则字符串相同也会返回负数 5 sprintf(savecfg,"%s\"ic_secret\":\"%s\"",savecfg,tmp_buff); 6 edit++; 7 } 8 } 9 ret = getKeyValueString(jsonmap2,"secret_fm",tmp_buff,sizeof(tmp_buff)); 10 if(ret>0){ 11 if(strcmp(usrcfg->ic_secret_fm,tmp_buff)!=0){ 12 if(edit>0) 13 sprintf(savecfg,"%s,\"ic_secret_fm\":\"%s\"",savecfg,tmp_buff); 14 else 15 sprintf(savecfg,"%s\"ic_secret_fm\":\"%s\"",savecfg,tmp_buff); 16 edit++; 17 } 18 } 19 ret = getKeyValueString(jsonmap2,"m1_secret_fm",tmp_buff,sizeof(tmp_buff)); 20 if(ret>0){ 21 if(strcmp(usrcfg->ic_m1_secret_fm,tmp_buff)!=0){ 22 if(edit>0) 23 sprintf(savecfg,"%s,\"ic_m1_secret_fm\":\"%s\"",savecfg,tmp_buff); 24 else 25 sprintf(savecfg,"%s\"ic_m1_secret_fm\":\"%s\"",savecfg,tmp_buff); 26 edit++; 27 } 28 } 29 if(edit!=0){ 30 sprintf(savecfg,"%s}",savecfg); 31 cJSON *roottmp = cJSON_Parse(savecfg); 32 if(roottmp){ 33 jsonConfigToConffile(roottmp,&code,0);//保存配置 34 cJSON_Delete(roottmp); 35 } 36 } 37 printf("ICSecret --- edit:%d,savecfg:%s\n",edit,savecfg);
上述方式也可以调用json库函数实现(更优,代码少)
cJSON* rootedit = cJSON_CreateObject(); if (rootedit == NULL) { return 0; } cJSON *jsonmap2 = cJSON_GetObjectItem(jsonmap1,"tass"); if(jsonmap2){ ret = getKeyValueString(jsonmap2,"secret",tmp_buff,sizeof(tmp_buff)); if(ret > 0 && strcmp(usrcfg->ic_secret,tmp_buff)!=0){// cJSON_AddStringToObject(rootedit,"ic_secret",tmp_buff); edit++; } ret = getKeyValueString(jsonmap2,"secret_fm",tmp_buff,sizeof(tmp_buff)); if(ret > 0 && strcmp(usrcfg->ic_secret_fm,tmp_buff)!=0){ cJSON_AddStringToObject(rootedit,"ic_secret_fm",tmp_buff); edit++; } ret = getKeyValueString(jsonmap2,"m1_secret_fm",tmp_buff,sizeof(tmp_buff)); if(ret > 0 && strcmp(usrcfg->ic_m1_secret_fm,tmp_buff)!=0){ cJSON_AddStringToObject(rootedit,"ic_m1_secret_fm",tmp_buff); edit++; } } char *tmp = cJSON_PrintUnformatted(rootedit);//CJSON的打印格式 log_info("edit secret:%s\n",tmp); if(tmp && strlen(tmp)>2){ jsonConfigToConffile(rootedit,&code,0);//保存配置 cJSON_Delete(rootedit); } if(tmp){ cJSON_free(tmp); tmp=NULL; }
四、strtok
什么时候使用?如要获取weixiao-config|wecard.qq.com|1652667671_A702F4BC233D712BFB1B38B28AA797E71676364978里的1652667671
result = strtok(indata,"|"); while(result != NULL ) { result = strtok(NULL,"|"); i++; if(i==2){//第三次就会获取到主体代码部分的字符串 break; } }
//结束获取到:1652667671_A702F4BC233D712BFB1B38B28AA797E71676364978 result = strtok(result,"_");//这里发现主体代码后还有一个'_',那再使用一次就可以获取到主体代码,,,也可以用截取的方式,指针位移到'_'截取的长度部分。
五、atoi
六、时间字符串和时间戳互相转换(在stm32上发现时间多了8小时,是时区的原因)
1 #include <stdio.h> 2 #include <string.h> 3 #include <time.h> 4 #include <stdlib.h> 5 6 /*标准时间转换为时间戳*/ 7 unsigned int standard_to_stamp(char *str_time)//"2023-03-02 15:13:40"; 8 { 9 struct tm stm; 10 int iY,iM,iD,iH,iMin,iS; 11 memset(&stm,0,sizeof(stm)); 12 iY = atoi(str_time); 13 iM = atoi(str_time+5); //和实际输入的格式 有关系 14 iD = atoi(str_time+8); 15 iH = atoi(str_time+11); 16 iMin = atoi(str_time+14); 17 iS = atoi(str_time+17); 18 19 stm.tm_year=iY-1900; 20 stm.tm_mon=iM-1; 21 stm.tm_mday=iD; 22 stm.tm_hour=iH; 23 stm.tm_min=iMin; 24 stm.tm_sec=iS; 25 26 printf("解析后的时间是%d-%02d-%02d %02d:%02d:%02d\n", iY, iM, iD, iH, iMin, iS); 27 28 return (unsigned int)mktime(&stm); 29 } 30 31 /*时间戳转换为标准时间*/ 32 typedef struct times 33 { 34 int Year; 35 int Mon; 36 int Day; 37 int Hour; 38 int Min; 39 int Second; 40 }Times; 41 42 Times stamp_to_standard(unsigned int stampTime) 43 { 44 time_t tick = (time_t)stampTime;//强制转换 如果传入的是毫秒级时间戳, 注意有的格式较严时应这样写:(time_t)(stamptime/1000) 45 struct tm tm; 46 char s[100]; 47 Times standard; 48 tm = *localtime(&tick); //tm.tm_hour 有的系统下要 +8,东八区,如果+8要判断 if(tm.tm_hour+8)>=24 tm.tm_hour -= 8; 49 strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", &tm); 50 printf("时间戳为:%d 转换成标准时间为(字符串): %s\n", (int)tick, s);//如果要转换为字符串,这里就可以return字符串了,不过注意返回的字符串要是全局或静态变量。 51 52 standard.Year = atoi(s); 53 standard.Mon = atoi(s+5); 54 standard.Day = atoi(s+8); 55 standard.Hour = atoi(s+11); 56 standard.Min = atoi(s+14); 57 standard.Second = atoi(s+17); 58 59 return standard;//再转换为结构体类型 60 } 61 62 int main(void) 63 { 64 /*int 范围:2147483648~2147483647,表示时间:2038-01-19 11:14:07 65 unsigned int范围:0~4294967295,表示时间:2106-02-07 14:28:15 66 linux下就是用unsigned long存时间,所以只能到2038年,原因是当时那个年代就认为32位字宽已经很大了 */ 67 68 Times standard; 69 unsigned int a =0; 70 char argv[]= "2023-03-02 15:13:40"; 71 printf("输入的标准时间是: %s \n",argv); 72 73 a=standard_to_stamp(argv); 74 printf("标准时间转换为时间戳: %d\n",a); 75 76 standard = stamp_to_standard(a); 77 printf("standard.year:%d\n",standard.Year); 78 79 return 0; 80 }
时间字符串和时间戳互相转换共用到三个库函数,包含在<time.h>下,分别为:
1、时间结构体转换为时间戳(传入时间结构体,返回时间戳)
2、时间戳转换为时间结构体(传入时间戳,返回时间结构体)
如下:localtime 运用实例:
struct tm *time; unsigned long long curSystime = XunLocGetUtc();//系统实时时间,毫秒级 /*C语言库函数操作time_t和结构体tm来自time.h*/ time_t tick = (time_t)(curSystime/1000); time = localtime(&tick);//S级时间戳转换为时间结构体 unsigned short tmp_hour = time->tm_hour+8; //东八区+8 世界标准时间即格林威治时间 北京时间与UTC的时差为 +8 if((tmp_hour == 24 && time->tm_min >= 1)||tmp_hour > 24){//>=00:01:00 -= 24 23+8 = 31-24 23:59:00=1439 00:00:00=1440 00:01:00=1 tmp_hour -= 24; } unsigned short currentMin = (tmp_hour*60)+time->tm_min; //获取每天的实时分钟
时间戳网页:时间戳(Unix timestamp)转换工具 - 在线工具 (tool.lu)