881@ snprintf函数使用总结

一:理论分析 snprintf。

参考案例:

https://blog.csdn.net/singledevil0/article/details/126344677?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22126344677%22%2C%22source%22%3A%22singledevil0%22%7Dhttps://blog.csdn.net/singledevil0/article/details/126344677?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22126344677%22%2C%22source%22%3A%22singledevil0%22%7D

snprintf和sprintf区别分析_喜欢打篮球的普通人的博客-CSDN博客_sprintf和snprintf的区别

【依赖头文件】

#include<stdio.h>

【函数原型】

int snprintf(char *str, size_t size, const char *format, …);

【函数参数】

str:目标字符串;size:拷贝字节数(Bytes); format:源字符串; …格式

【函数功能】

最多从源字符串format中拷贝size字节的内容(含字符串结尾标志’\0’)到目标字符串

The functions snprintf() write at most size bytes (including the terminating null byte (’\0’)) to str.

【返回值】

成功返回源串的长度(strlen, 不含’\0’)

失败返回负值

【例子及理解】

由于最多拷贝size个字节到目标字符串,那么通常目标字符串就设置成size大小就不会有越界问题

下面将目标字符串的长度设置为size大小,分别实验源串长度小于,等于,大于size的情况

【情形一】:源串小于目标字符串

实际上源串为:“123\0”,所以只将字符’1’,‘2’,‘3’, '\0’ 拷到了目标串, 返回值为源串的strlen为3

  1 #include <stdio.h>
  2 #include <strings.h>
  3 #include <string.h>
  4 int main(void)
  5 {   
  6     char a[10] = {'\0'};
  7     int i = 0;
  8     int ret = 0;
  9     memset(a, 1, sizeof(a));
 10     for(i = 0; i < 10; i++)
 11     {   
 12         printf("a[%d] = %d\n",i,a[i]);
 13     }
 14     
 15     ret = snprintf(a, 10, "%d", 123);
 16     printf("ret = %d\n",ret);
 17     
 18     for(i = 0; i < 10; i++)
 19     {
 20         printf("a[%d] = %d\n",i,a[i]);
 21     }
 22     return 0;
 23 }   
root@ubuntu:/shiyan/shiyan265# gcc snprintf.c 
root@ubuntu:/shiyan/shiyan265# ./a.out
a[0] = 1
a[1] = 1
a[2] = 1
a[3] = 1
a[4] = 1
a[5] = 1
a[6] = 1
a[7] = 1
a[8] = 1
a[9] = 1
ret = 3
a[0] = 49
a[1] = 50
a[2] = 51
a[3] = 0
a[4] = 1
a[5] = 1
a[6] = 1
a[7] = 1
a[8] = 1
a[9] = 1
root@ubuntu:/shiyan/shiyan265# 

%d 打印格式,所以会把 1/2/3 拆分,最终输出的是 ASCII 码,

十进制的格式,所以1对应49 以此类推: 

【情形二】:源串等于目标字符串

源串为"abcdefghi\0", 正好将源串拷贝到目标字符串中,返回值为源串的strlen为9

1 #include <stdio.h>
2 #include <strings.h>
3 #include <string.h>
4 int main(void)
5 {   
6     char a[10] = {'\0'};
7     int i = 0;
8     int ret = 0;
9     memset(a, 1, sizeof(a));
10     for(i = 0; i < 10; i++)
11     {   
12         printf("a[%d] = %d\n",i,a[i]);
13     }
14     
15     //ret = snprintf(a, 10, "%d", 123);
16     ret = snprintf(a, 10, "%s","abcdefghi");
17     printf("ret = %d\n",ret);
18     
19     for(i = 0; i < 10; i++)
20     {   
21         printf("a[%d] = %d\n",i,a[i]);
22     }
23     return 0;
root@ubuntu:/shiyan/shiyan265# gcc snprintf.c 
root@ubuntu:/shiyan/shiyan265# ./a.out

a[0] = 1
a[1] = 1
a[2] = 1
a[3] = 1
a[4] = 1
a[5] = 1
a[6] = 1
a[7] = 1
a[8] = 1
a[9] = 1
ret = 9
a[0] = 97
a[1] = 98
a[2] = 99
a[3] = 100
a[4] = 101
a[5] = 102
a[6] = 103
a[7] = 104
a[8] = 105
a[9] = 0
root@ubuntu:/shiyan/shiyan265# 

【情形三】源串大于目标字符串

源串为"abcdefghijklmnopq\0",最多从源串拷贝10个字节(含\0)到目标串那么就是拷贝源串的9个字节内容(abcdefghi)再加一个\0到目标串,

目标串的结果和情形二一样,但是ret返回值变成了17, 即strlen(“abcdefghijklmnopq”)

  1 #include <stdio.h>
  2 #include <strings.h>
  3 #include <string.h>
  4 int main(void)
  5 {
  6     char a[10] = {'\0'};
  7     int i = 0;
  8     int ret = 0;
  9     memset(a, 1, sizeof(a));
 10     for(i = 0; i < 10; i++)
 11     {
 12         printf("a[%d] = %d\n",i,a[i]);
 13     }
 14 
 15     //ret = snprintf(a, 10, "%d", 123);
 16     //ret = snprintf(a, 10, "%s","abcdefghi");
 17     ret = snprintf(a, 10, "%s", "abcdefghijklmnopq");
 18     printf("ret = %d\n",ret);
 19 
 20     for(i = 0; i < 10; i++)
 21     {
 22         printf("a[%d] = %d\n",i,a[i]);
 23     }
 24     return 0;
 25 }

root@ubuntu:/shiyan/shiyan265# gcc snprintf.c 
root@ubuntu:/shiyan/shiyan265# ./a.out

a[0] = 1
a[1] = 1
a[2] = 1
a[3] = 1
a[4] = 1
a[5] = 1
a[6] = 1
a[7] = 1
a[8] = 1
a[9] = 1
ret = 17
a[0] = 97
a[1] = 98
a[2] = 99
a[3] = 100
a[4] = 101
a[5] = 102
a[6] = 103
a[7] = 104
a[8] = 105
a[9] = 0
root@ubuntu:/shiyan/shiyan265# 

=======================================================================

函数原型:int snprintf(char* dest_str,size_t size,const char* format,…);

所需头文件:#include<stdio.h>

函数功能:

先将可变参数 “…” 按照format的格式格式化为字符串,然后再将其拷贝至dest_str中。

注意事项:

如果格式化后的字符串长度小于size,则将字符串全部拷贝至dest_str中,并在字符串结尾处加上‘\0’;
如果格式化后的字符串长度大于或等于size,则将字符串的(size-1)拷贝至dest_str中,然后在字符串结尾处加上’\0’.
函数返回值是 格式化字符串的长度。

实例:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  

int main(void){  

    char dest_str[1024];  
    memset(dest_str,0,sizeof(dest_str));  

    char *s1 = "Linux C程序设计";  
    int size = strlen(s1);  
    int year = 2017;  
    int month = 9;  
    int day = 8;  

    snprintf(dest_str,sizeof(dest_str),"字符串:%s\n长度是:%d\n今天是:%d年%d月%d日\n",s1,size,year,month,day);  

    printf("%s",dest_str);  

    return 0;  
}  
执行结果
字符串:Linux C程序设计
长度是:15
今天是:2017年9月8日

这个函数主要是在android hal 层中广泛用到。

%u 无符号十进制整数
%x 使用十六进制数字0f的无符号十六进制整数
%b 这个在基础阶段用不到,我也没试过,下面是我找的资料

%b 就是boolean的意思 以下是1.5 api中的解释
'b', 'B' 常规 如果参数 arg 为 null,则结果为 "false"。如果 arg 是一个 boolean 值或 Boolean,则结果为 String.valueOf() 返回的字符串。否则结果为 "true"。

二:案例剖析, snprintf 函数在  device_create_file  中的应用。

DEVICE_ATTR是一个宏,其定义在  include/linux/device.h:

#define DEVICE_ATTR(_name, _mode, _show, _store) \
    struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
__ATTR宏定义在include/linux/sysfs.h:

#define __ATTR(_name,_mode,_show,_store) { \
    .attr = {.name = __stringify(_name), .mode = _mode },   \
    .show   = _show,                                        \
    .store  = _store,                                       \
}

struct device_attribute结构定义在include/linux/device.h:

/* interface for exporting device attributes */
struct device_attribute {
    struct attribute    attr;
    ssize_t (*show)(struct device *dev, struct device_attribute *attr,char *buf);
    ssize_t (*store)(struct device *dev, struct device_attribute *attr,const char *buf, size_t count);
};
DEVICE_ATTR宏展开:
#define DEVICE_ATTR(_name, _mode, _show, _store) \
    struct device_attribute dev_attr_##_name = { \
        .attr = {.name = __stringify(_name), .mode = _mode },   \
        .show   = _show,                                        \
        .store  = _store,                                       \
    }
举例说明DEVICE_ATTR使用方法:
static DEVICE_ATTR(msm_gpio, 0664, msmgpio_show, msmgpio_store);
 
static ssize_t msmgpio_show(struct device *dev, struct device_attribute *attr, char *buf)
{
    int temp[5];
    struct gpio_data *gpio_data_ptr = dev_get_drvdata(dev);
 
    temp[0] = gpio_get_value(gpio_data_ptr->gpio0);
    temp[1] = gpio_get_value(gpio_data_ptr->gpio2);
    temp[2] = gpio_get_value(gpio_data_ptr->gpio3);
    temp[3] = gpio_get_value(gpio_data_ptr->gpio10);
    temp[4] = gpio_get_value(gpio_data_ptr->gpio11);
 
 return snprintf(buf, 6, "%d%d%d%d%d", temp[0], temp[1],temp[2], temp[3], temp[4]);
}
 
static ssize_t msmgpio_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{
    struct gpio_data *gpio_data_ptr = dev_get_drvdata(dev);
 
    gpio_set_value(gpio_data_ptr->gpio0,  (buf[0] == '1') ? 1 : 0);
    gpio_set_value(gpio_data_ptr->gpio2,  (buf[1] == '1') ? 1 : 0);
    gpio_set_value(gpio_data_ptr->gpio3,  (buf[2] == '1') ? 1 : 0);
    gpio_set_value(gpio_data_ptr->gpio10, (buf[3] == '1') ? 1 : 0);
    gpio_set_value(gpio_data_ptr->gpio11, (buf[4] == '1') ? 1 : 0);
 
    return size;
}
 
static DEVICE_ATTR(msm_gpio, 0664, msmgpio_show, msmgpio_store);
之后在驱动的probe函数中即可调用device_create_file:

err = device_create_file(&dev->dev, &dev_attr_msm_gpio);
if (err) {
        dev_err(&dev->dev, "sys file creation failed\n");
        return -ENODEV;
}


device_create_file和device_remove_file 定义在drivers/base/core.c中,声明在include/linux/device.h中,device_create_file返回0代表创建成功。


int device_create_file(struct device *dev, const struct device_attribute *attr)
{
    int error = 0;
 
    if (dev) {
        WARN(((attr->attr.mode & S_IWUGO) && !attr->store), "Attribute %s: write permission without 'store'\n", attr->attr.name);
        WARN(((attr->attr.mode & S_IRUGO) && !attr->show), "Attribute %s: read permission without 'show'\n", attr->attr.name);
        error = sysfs_create_file(&dev->kobj, &attr->attr);
    }
 
    return error;
}
 
void device_remove_file(struct device *dev, const struct device_attribute *attr)
{
    if (dev)
        sysfs_remove_file(&dev->kobj, &attr->attr);
}


在文件系统/sys/devices/soc.0/gpio_ctrl.72下面生成msm_gpio节点,用cat,echo操作硬件:
root@msm8909:/sys/devices/soc.0/gpio_ctrl.72 # ls -l msm_gpio                  
-rw-rw-r-- root     root         4096 1970-01-01 00:02 msm_gpio
root@msm8909:/sys/devices/soc.0/gpio_ctrl.72 # cat msm_gpio
00000
root@msm8909:/sys/devices/soc.0/gpio_ctrl.72 # echo 11111 > msm_gpio


 

三:案例解析:

将SN号根据* 进行区分,然后打印出来规范的格式化数据:
    apaota_test
    open & init /lib64/libapa_ota.so success
    usage: apaota_test
    example: ./apaota_test
    [568] apa_get_software_version
    version_apa [full-SN] : CG019028 357 81875*704000604AA*00.02.00_13.00.03*9BJ*
    [579] apa_get_software_version sn: CG019028 357 81875
    [585] apa_get_software_version part_number: 704000604AA
    [591] apa_get_software_version sf version: 00.02.00
    [593] apa_get_software_version hw version: 13.00.03
    [600] apa_get_software_version Supplier_number: 9BJ
    json: {"sn":"CG019028 357 81875","part_no":"704000604AA","vendor_id":"9BJ","calib_version":""}



typedef struct  {
    char  slot_version[BUF_SIZE];
    char  boot_version[BUF_SIZE];
    char  soft_version[BUF_SIZE];
    char  hard_version[BUF_SIZE];
    char     vendor_id[BUF_SIZE];
    char    extra_info[BUF_SIZE];
}ecu_version_info;

int main(int argc, char **argv)
{
	char *libpath = "/lib64/libapa_ota.so";
	unsigned char status;
	unsigned short x_axis;
	unsigned short y_axis;
	int ret = 0;

	apa_update_libapi_init_test(libpath);

	memset(&apa_cur_version, 0, sizeof(ecu_version_info));

	if (argc == 1) {
		printf("usage: %s   \nexample: ./apaota_test\n", argv[0]);
		if (apa_get_version_api_test != NULL) {
			ret = apa_get_version_api_test(0, &apa_cur_version);
			//printf("call apa_get_version_api_test api ret=%d\n",ret);
			printf("json: %s", apa_cur_version.extra_info);
		} else {
			printf("call apa_get_version_api_test api = NULL\n");
		}
		return 0;

	} 
}

int apa_get_software_version(int mode, ecu_version_info *version)
{
	if(version == NULL)
	{
		printf("[%d] apa_get_software_version\n", __LINE__);
		return -1;
	}

        char sn[256] = { 0 };
	char part_number[256] = { 0 };
	char Supplier_number[256] = { 0 };
	char calib_version[256]="";
	unsigned char writebuf[APA_VER_NOTIFY_SIZE] = { 0 };

	unsigned char readbuf[1024] = { 0 };
	unsigned char version_apa[1024] = { 0 };

	//   char respbuf[APA_VER_RESP_SIZE] = {0};    
	int ret = 0;
	unsigned char crcval;
	unsigned int fixed_header = UART_FRAME_FIX_HEADER;
	unsigned short cmd_id = APA_VER_MESG_ID;
	char i = 0x00;
	unsigned char *last_pos = NULL, *pos = NULL, *underline_pos = NULL;
	int count = 0;

	memset(version, 0, sizeof(ecu_version_info));
	ret = apaota_uart_init();
	if (ret != 0) {
		printf("i2c init fail\n");
		return -1;
	}

	apa_common_info_configure(&writebuf[0], fixed_header, cmd_id);
	writebuf[4] = 0x00;			//framelen
	writebuf[5] = 0x0d;			//framelen

	writebuf[6] = 0x01;			//msg type
	writebuf[9] = 0x00;			//msg size
	writebuf[10] = 0x01;		//msg size
	writebuf[11] = 0x00;		//msg priorty

	crcval = crcBBC((unsigned char *)&writebuf[0], sizeof(writebuf));
	writebuf[12] = crcval;

	memset(readbuf, 0, 1024);
	ret = uart_transmit_msg_with_resp(writebuf, APA_VER_NOTIFY_SIZE, readbuf, 66);
	if (ret < 0) {
		printf("read err ret : %d\n", ret);
	}
#if 0
	LOGE("uart_transmit_msg_with_resp cmd :");
	for (i = 0; i < 66; i++) {
		LOGE("readbuf[%d] : 0x%x\n", i, readbuf[i]);
	}
	LOGE("uart_transmit_msg_with_resp cmd end");
#endif
	memcpy(version_apa, &readbuf[12], readbuf[10]);

	printf("[%d] apa_get_software_version\n", __LINE__);
	printf("version_apa [full-SN] :  %s \n", version_apa);
	last_pos = version_apa;
	pos = version_apa;
	
	while(last_pos && pos)
	{
		pos = (unsigned char *)strchr((char*)last_pos, '*');
		if(count == 0)  //sn
		{
			memcpy(sn, last_pos, (pos - last_pos));
			printf("[%d] apa_get_software_version sn: %s\n", __LINE__, sn);
		}	
		if(count == 1)  //part_number
		{
			memcpy(part_number, last_pos, (pos - last_pos));
			//memcpy(version->part_number, last_pos, (pos - last_pos));
			printf("[%d] apa_get_software_version part_number: %s\n", __LINE__, part_number);
		}
		else if(count == 2) // hardware/soft ware version
		{
			underline_pos = (unsigned char *)strchr((char *)last_pos, '_');
			memcpy(version->soft_version, last_pos, (underline_pos - last_pos));
			printf("[%d] apa_get_software_version sf version: %s\n", __LINE__, version->soft_version);
			memcpy(version->hard_version, underline_pos + 1, (pos - underline_pos -1));
			printf("[%d] apa_get_software_version hw version: %s\n",  __LINE__, version->hard_version);

		}
		else if(count == 3) // Supplier_number
		{
			memcpy(Supplier_number, last_pos, (pos - last_pos));
			//memcpy(version->Supplier_number, last_pos, (pos - last_pos));
			printf("[%d] apa_get_software_version Supplier_number: %s\n", __LINE__, Supplier_number);
		}
		count++;
		last_pos = pos + 1;
	}
	
//格式化串,按照具体的格式打印出来:
	snprintf(version->extra_info,sizeof(version->extra_info),"{\"sn\":\"%s\",\"part_no\":\"%s\",\"vendor_id\":\"%s\",\"calib_version\":\"%s\"}",sn,part_number,Supplier_number,calib_version);
//	snprintf(version->vendor_id,sizeof(version->vendor_id),"{\"sn\":\"%s\",\"part_no\":\"%s\",\"vendor_id\":\"%s\",\"calib_version\":\"%s\"}",sn,part_number,Supplier_number,calib_version);
	apaota_uart_deinit();

	return 0;
}

参考1: https://blog.csdn.net/liaojunwu/article/details/80489406
参考2: https://blog.csdn.net/qq_34707315/article/details/77895735

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值