IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 各种printf总结 -> 正文阅读

[嵌入式]各种printf总结

编程中printf是每个人都很熟悉的,但是与printf相关的那些函数你了解过吗?这里总结一下。

printf

功能:很常用的printf函数,用于将数据以特定的格式输出到标准输出设备stdout(通常就是我们的终端界面)。

函数声明:

int printf(const char *format, ...)

返回值:int类型数据。看到没,其实printf是有返回值的,而且是int类型,printf的返回值就是printf打印出的字符串的长度。因字符串末尾有一个’\0’,故返回值是位数加一。

参数:

  • format:格式说明。
  • ...:变长参数列表

dprintf

功能:将数据写入指定的文件描述符。注意与fprintf的区别,二者数据写入对象不同,dprintf指定只能写入文件描述符所指定的文件中。

函数声明:

int dprintf(int fd, const char *format, ...);

返回值:int类型。

参数:

  • fd:文件描述符
  • format:格式说明
  • ...:变长参数列表

dprintf用的不多,反正我是没怎么用过,可能接触到linux内核的话使用的比较多吧。

fprintf

功能:将数据以标准格式输出到流steam中。参考链接.

函数声明:

int fprintf(FILE *stream, const char *format, ...)

返回值:int类型数据。

参数:

  • stream:指向 FILE 对象的指针,该 FILE 对象标识了流。
  • format:格式说明。
  • ...:变长参数

fprintf挺常用的,通常配合fopen、fclose使用。这里注意fprintf是将数据以字符的形式写入流中的,即使我们写的是int类型的数据,也是转化成了字符进行写入的。

比如我们使用fprintf将54写入stream,那么54就会被分别以'5'和'4'写入到stream,共占据两个字节,同样,如果写入100,那么就会占据三个字节。

这里要跟fwrite做一个区别,fwrite也是想流stream中写入数据,但是fwrite是以二进制的格式将数据写入的,即我们写入整形数据54的话,是以int类型进行存储的,占用4字节,存储100时也是一样,同样是int类型数据,所以占据的空间也是4字节。

fwrite是将数据不经转换直接以二进制的形式写入文件,而fprintf是将数据转换为字符后再写入文件。参考链接.

vfprintf

函数功能:将参数列表以标准格式输出到流stream中。

函数声明:

int vfprintf(FILE *stream, const char *format, va_list arg)

参数:

  • stream:指向 FILE 对象的指针,该 FILE 对象标识了流。
  • format:跟上面的一样,是格式说明。
  • arg:参数列表。

返回值:int数据

vfprintf与fprintf的区别,在于第三个参数的形式。比如要写一个自定义log接口,自己体会一下:

void log(FILE *file, const char* format, ... )
{
    va_list args;
    va_start (args, format);
    fprintf(file, "%s: ", getTimestamp());
    vfprintf (file, format, args);      //在这个地方用vfprintf函数就很合适,因为第三个参数可以直接得到
    va_end (args);
}

vprintf

函数功能:使用参数列表将数据输出到stdout标准输出设备。

函数声明:

int vprintf(const char *format, va_list arg)

返回值:int类型数据。

参数:不写了,跟上面的一样。

这里与vfprintf功能相似,就是输出对象改成了标准输出,所以就隐藏不写了,那就没什么好说的了,参考vfprintf。

sprintf

函数功能:发送格式化输出到字符串

函数声明:

int sprintf(char *str, const char *format, ...)

返回值:写入成功返回写入的字符总数,失败返回一个负数。

参数:

  • str:字符串指针
  • format:格式说明
  • ...:变长参数

这里需要注意str指向的内存空间的地址大小要保证能够存放的下format指定的数据内容,否则会出现缓冲区溢出问题,所以这个函数使用起来不安全,有缓冲区溢出的风险。

更安全的使用请参考snprintf。

asprintf

函数功能:sprintf增强版,能够根据格式化字符串长度申请内存空间,保证不会有缓冲区溢出风险。原生级别防止缓冲区溢出。

函数声明:

int asprintf(char **strp, const char *fmt, ...);

返回值:成功返回写入的字符总数,失败返回一个负数。

参数:

  • strp:指向存放自动申请内存空间的地址的指针。
  • fmt:格式化说明。
  • ...:变长参数

这里执行完asprintf后,strp会指向一个已经申请好的内存指针,需要注意的是这块自动申请的内存需要手动释放,比如:

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

int main()
{
    char *buf;
    if (asprintf(&buf, "%s-%d", "tesdjkjsdlgjdt", 1334) < 0) {
        printf("asprintf error!\n");
        return;
    }

    printf("buf:%s\n", buf);
    printf("strlen(buf):%d\n", strlen(buf));

    free(buf);

}

vsprintf

函数功能:使用参数列表发送格式化输出到字符串。

函数声明:

int vsprintf(char *str, const char *format, va_list arg)

返回值:如果成功,则返回写入的字符总数,否则返回一个负数。

这个函数与sprintf类似,除了第三个参数,这里比较一下第三个参数,这里用的是va_list,sprintf的第三个参数是...,二者的区别是什么?

...表示的是任意个数的参数,va_list是一种参数列表,通过va_star和va_end可以从...中获取所有的参数,然后把它们组织到va_list中,供程序使用,可以简单理解为可变参数从...中存放到了va_list后才能被程序使用。(可能这样理解太肤浅了,具体原理网上有详细介绍,这里只是为方便理解这样说的。)

与sprintf一样,这里还是有缓冲区溢出的风险。

snprintf

函数功能:将格式化的数据写入字符串。

函数声明:

 int snprintf(char *str, int n, char * format, ...);

返回值:成功则返回参数str 字符串长度,失败则返回-1,错误原因存于errno 中。

参数:

  • str:要写入的字符串指针
  • n:写入的长度(注意这里对写入的长度有限制,与sprintf的区别)
  • format:格式说明
  • ...:可变参数

上面数到sprintf有缓冲区溢出风险,而asprintf从接口上就杜绝了这种风险,因为它会给目标指针分配足够大的空间来写入数据。这里的snprintf则是从使用者角度提供了规避缓冲区溢出风险的方法,使用者可以指定写入长度从而确保不会拷贝过多数据到目标内存空间,如果使用者太傻,还是会有风险,相比较而言,我觉得asprintf挺安全的,就是使用完毕后需要手动释放申请的内存空间,这个不能忘记。

vsnprintf

函数功能:将可变参数格式化输出到一个字符数组。

函数声明:

int vsnprintf(char *str, size_t size, const char *format, va_list arg)

参数:不说了

返回值:执行成功,返回写入到字符数组str中的字符个数(不包含终止符),最大不超过size;执行失败,返回负值,并置errno.

跟vsprintf类似,只不过加上了防止缓冲区溢出的措施,通过指定输出字符个数来规避这种风险。

总结

这些是我从公司项目源代码中所使用到的与printf相关的函数,寻找办法是先使用source insight建立源码工程,然后搜索printf关键字的所有结果,保存输出结果为文件。然后使用python正则表达式匹配出所有与printf相似的字段名称,找到了这些函数。

里面呢有我经常用到的printf、sprintf、snprintf,fprintf。其中vfprintf之前做自定义日志接口时用到了,觉得还是挺有用的。其他平时没怎么用到但是有些还是给我的感觉还是挺有用的,比如asprinf竟然可以自动帮助申请内存,还挺有意思的。其他的一些我觉得功能还是挺强大的,以后需要的时候可以用一下。

贴上python代码吧,说实话python做这些小辅助工具还挺好用的,不是说python就适合做小工具,而是说明python的用途是多种多样的,大到人工智能,小到小工具,简直了。

import re

BUFFSIZE = 65536

result = []

def find_printf(line):
    matchs = re.findall(r'[a-zA-Z]*printf', line)
    for match in matchs:
        if match in result:
            continue
        elif match not in result:
            result.append(match)

with open('result') as f:
    while 1:
        try:
            lines = f.readlines(BUFFSIZE)
        except UnicodeDecodeError:
            print('UnicodeDecodeError')
            pass
        if not lines:
            break
        for line in lines:
            find_printf(line)
            #print(line)

print(result)
print(len(result))
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-05-05 11:35:52  更:2022-05-05 11:36:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 2:41:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码