Linux下实现自己的printf函数

news2024/12/23 12:55:53

Linux下实现自己的printf函数


文章目录

  • Linux下实现自己的printf函数
  • 项目中的使用
  • 实现自己的printf函数


项目中的使用

/**********************************************************************
 * 函数名称: DebugPrint
 * 功能描述: 打印信息的总入口函数
 *            程序里用DBG_PRINTF来打印, 它就是DebugPrint
 *            在config.h里有这样的宏定义: #define DBG_PRINTF DebugPrint
 * 输入参数: 可变参数,用法和printf完全一样
 * 输出参数: 无
 * 返 回 值: 0   - 成功
 *            -1  - 失败
 ***********************************************************************/
int DebugPrint(const char *pcFormat, ...)
{
    char strTmpBuf[1000];
    char *pcTmp;
    va_list tArg;
    int iNum;
    PT_DebugOpr ptTmp = g_ptDebugOprHead;
    int dbglevel = DEFAULT_DBGLEVEL;

    /* 可变参数的处理, 抄自glibc的printf函数 */
    va_start (tArg, pcFormat);
    iNum = vsprintf (strTmpBuf, pcFormat, tArg);
    va_end (tArg);
    strTmpBuf[iNum] = '\0';


    pcTmp = strTmpBuf;
    
    /* 根据打印级别决定是否打印 */
    if ((strTmpBuf[0] == '<') && (strTmpBuf[2] == '>'))
    {
        dbglevel = strTmpBuf[1] - '0';
        if (dbglevel >= 0 && dbglevel <= 9)
        {
            pcTmp = strTmpBuf + 3;
        }
        else
        {
            dbglevel = DEFAULT_DBGLEVEL;
        }
    }

    if (dbglevel > g_iDbgLevelLimit)
    {
        return -1;
    }

    /* 调用链表中所有isCanUse为1的结构体的DebugPrint函数 
     * 用来输出调试信息
     */
    while (ptTmp)
    {
        if (ptTmp->isCanUse)
        {
            ptTmp->DebugPrint(pcTmp);
        }
        ptTmp = ptTmp->ptNext;
    }

    return 0;
    
}

在这里插入图片描述

代码分析
该代码段是一个调试打印函数DebugPrint的实现。下面对代码进行详细分析:

函数签名:int DebugPrint(const char *pcFormat, …)

返回类型:int,表示函数执行结果的状态,成功为0,失败为-1。
参数:const char *pcFormat,格式化字符串,用于指定输出的格式和内容。
可变参数:…,用于传递格式化字符串中的变量参数。
局部变量:

char strTmpBuf[1000]:临时缓冲区,用于存储格式化后的字符串。
char *pcTmp:临时指针,用于指向待输出的字符串。
va_list tArg:可变参数列表对象,用于存储和访问可变参数。
int iNum:格式化后的字符串长度。
PT_DebugOpr ptTmp:指向调试操作结构体的临时指针。
int dbglevel:调试级别,默认为DEFAULT_DBGLEVEL。
可变参数处理:

va_start(tArg, pcFormat):初始化可变参数列表,将tArg指向第一个可变参数。
iNum = vsprintf(strTmpBuf, pcFormat, tArg):使用格式化字符串和可变参数列表将数据格式化到临时缓冲区strTmpBuf中,并返回格式化后的字符串长度。
va_end(tArg):清理可变参数列表。
字符串处理:

strTmpBuf[iNum] = ‘\0’:将临时缓冲区的最后一个字符设置为字符串结束符。
pcTmp = strTmpBuf:将临时指针指向临时缓冲区的起始位置。
调试级别处理:

如果格式化后的字符串以开头(x是一个0到9之间的数字),则将dbglevel设置为x。
dbglevel = strTmpBuf[1] - ‘0’:将字符转换为数字。
如果转换结果在0到9之间,将pcTmp指向strTmpBuf中跳过调试级别标识的位置。
否则,将dbglevel重置为DEFAULT_DBGLEVEL。
如果调试级别大于设置的最大调试级别g_iDbgLevelLimit,直接返回。
遍历调试操作结构体链表:

while (ptTmp):循环遍历链表,直到遍历到最后一个节点(NULL)。
如果当前结构体的isCanUse标志为1,表示该结构体可用,则调用该结构体的DebugPrint函数打印调试信息,传入的参数为pcTmp。
ptTmp = ptTmp->ptNext:指向下一个调试操作结构体。
返回值:

函数执行成功返回0,表示调试信息已输出。
如果调试级别超过了最大调试级别,函数直接返回-1,表示未输出调试信息。
该函数的作用是根据给定的调试级别和格式化字符串,将调试信息输出到所有可用的调试操作结构体中。函数首先将格式化字符串处理成可读的字符串,并根据调试级别判断是否输出调试信息。然后,遍历调试操作结构体链表,将调试信息传递给每个可用的结构体进行输出。

实现自己的printf函数

va_start、vsprintf 和 va_end 是 C 语言中的三个宏,它们通常一起使用来处理可变参数函数。

  • va_start
    宏用于初始化一个指向参数列表的 va_list 对象,该对象可以被后续的 va_arg 宏用于逐个访问参数列表中的每个参数。va_start 宏需要两个参数:第一个参数是一个 va_list 对象,第二个参数是可变参数函数中的最后一个命名参数,用于确定参数列表的开始位置。
  • vsprintf
    函数是一个可变参数函数,它可以将格式化的字符串和参数列表中的值按照指定的格式写入到一个字符串缓冲区中。vsprintf 函数需要三个参数:第一个参数是指向目标字符串缓冲区的指针,第二个参数是格式化字符串,第三个参数是一个 va_list 对象,该对象包含了要写入到字符串缓冲区中的参数列表。
  • va_end
    宏用于清理 va_list 对象,并释放它所占用的资源。它需要一个参数,即要清理的 va_list 对象。

下面是一个简单的示例,它演示了如何使用这三个宏来处理可变参数函数:

#include <stdio.h>
#include <stdarg.h>

void my_printf(char *format, ...) {
    va_list args;
    va_start(args, format);
    vprintf(format, args);
    va_end(args);
}

int main() {
    my_printf("Hello, %s! The answer is %d\n", "world", 42);
    return 0;
}

在上面的示例中,我们定义了一个名为 my_printf 的函数,它接受一个格式化字符串和可变数量的参数。在函数内部,我们首先使用 va_start 宏初始化一个 va_list 对象,然后使用 vprintf 函数和该对象来输出格式化字符串和参数列表中的值。最后,我们使用 va_end 宏清理 va_list 对象。在 main 函数中,我们调用了 my_printf 函数,并传递了一个格式化字符串和两个参数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/653097.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nodejs四、npm与包

零、文章目录 Nodejs四、npm与包 1、包 &#xff08;1&#xff09;包是什么 Node.js 中的第三方模块又叫做包。就像电脑和计算机指的是相同的东西&#xff0c;第三方模块和包指的是同一个概念&#xff0c;只不过叫法不同。 &#xff08;2&#xff09;包的来源 不同于 Nod…

Linux SSH PublicKey 登录

前言 ssh 远程登录密码认证的方式有 Password、Keyboard Interactive 和 Public Key 三种主要方式。 前面两种方式就是密码认证&#xff0c;含义都是一样大同小异。第三种是登录方式最安全的一种&#xff0c;也是我们常用的云服务器默认使用的一种方式。 本文就如何配置并使用…

torchvision.ops.nms实现NMS

nms原理&#xff1a; 当目标检测模型对一个目标有多个检测框时&#xff0c;需要滤掉多余的框&#xff0c;留下最接近真实目标的框。 步骤是这样的&#xff1a; 1.先把目标框初筛一波&#xff0c;比如设阈值为0.25, 把预测概率 < 0.25的目标框滤掉。 2.把 每个类别的 目标框 …

DEVONthink 3:Mac文档管理工具,知识管理app

DEVONthink Pro是一款功能强大的文档管理软件&#xff0c;它可以帮助用户高效地组织、管理和查找各种类型的文件和信息。 下面是DEVONthink Pro的主要特点介绍&#xff1a; 多功能性&#xff1a;DEVONthink Pro支持多种文件类型和数据源&#xff0c;并提供全面的搜索、分类、过…

在 ZBrush、Substance 3D Painter 和 UE5 中创作警探角色(P1)

小伙伴们大家好&#xff0c;今天瑞云渲染小编给大家分享的是自由CG艺术家Jean Zoudi创建《极乐迪斯科》的警探角色的项目花絮&#xff0c;会解释身体和服装的建模方式&#xff0c;分享角色发型和面部毛发背后的工作流程&#xff0c;也会详细介绍渲染过程。 介绍 大家好&#…

性能测试怎么做?性能测试策略配套适用场景,打通性能测试...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、常见的测试策略…

直流对数放大器

Logarithmic Amplifiers 对数放大器的应用场合 在雷达和一些其他测距的场合&#xff0c;sensor输出的信号的动态范围比较宽&#xff0c;也就是要求sensor输出的弱信号时有比较大的放大倍数&#xff0c;强的信号有较小的放大倍数&#xff0c;以保证sensor输出的信号经过放大器后…

可移动硬盘无媒体是什么意思?移动硬盘显示无媒体数据如何恢复

案例分享&#xff1a;【最近我遇到了一个麻烦&#xff0c;我的移动硬盘突然显示“无媒体”。我不知道发生了什么&#xff0c;我很担心我的硬盘中存储的大量重要数据是否还能恢复。我该怎么解决移动硬盘显示无媒体问题呢&#xff0c;求大神帮帮我吧&#xff01;&#xff01;&…

浏览器是如何实现生成HTTP消息的

我们经常会使用浏览器访问各种网站&#xff0c;获取各种信息&#xff0c;帮助解决工作生活中的问题。那你知道&#xff0c;浏览器是怎么帮助我们实现对web服务器的访问&#xff0c;并返回给我们想要的信息吗&#xff1f; 1. 浏览器生成HTTP消息 我们平时使用的浏览器有很多种&…

【强烈推荐】 十多款2023年必备国内外王炸级AI工具 (免费 精品 好用) 让你秒变神一样的装逼佬感受10倍生产力 (6) AI学习

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…

【LLMs系列】90%chatgpt性能的小羊驼Vicuna模型学习与实战

一、前言 UC伯克利学者联手CMU、斯坦福等&#xff0c;再次推出一个全新模型70亿/130亿参数的Vicuna&#xff0c;俗称「小羊驼」&#xff08;骆马&#xff09;。小羊驼号称能达到GPT-4的90%性能 github 地址: GitHub - lm-sys/FastChat: An open platform for training, servi…

ChatGPT爆火网络背后的故事?

文章目录 前言一、ChatGPT的诞生背景二、ChatGPT的技术原理三、ChatGPT的推广策略四、ChatGPT的未来展望五、橙子送书第2期 前言 ChatGPT是一款基于人工智能技术的聊天机器人&#xff0c;它的出现引起了广泛的关注和热议。在短短的时间内&#xff0c;ChatGPT就成为了全球范围内…

实测|飞凌嵌入式OK3588-C开发板4G模组的使用与测试

本篇试用报告由发烧友 ouxiaolong提供&#xff0c;感谢ouxiaolong的支持。飞凌嵌入式会持续开展开发板有奖试用活动&#xff0c;更有京东E卡等着你&#xff01;欢迎大家的持续关注。 飞凌嵌入式OK3588-C开发板是一款性能强劲的旗舰产品&#xff0c;采用核心板底板的分体式设计…

linuxOPS系统服务_Linux下用户管理

用户概念以及基本作用 **用户&#xff1a;**指的是Linux操作系统中用于管理系统或者服务的人 一问&#xff1a;管理系统到底在管理什么&#xff1f; 答&#xff1a;Linux下一切皆文件&#xff0c;所以用户管理的是相应的文件 二问&#xff1a;如何管理文件呢&#xff1f; …

JDK、JRE、JVM三者的区别

JDK&#xff08;Java Development Kit&#xff09;&#xff1a;Java开发工具包 JRE&#xff08;Java Runtime Environment&#xff09;&#xff1a;Java运行环境 JVM&#xff08;Java Virtual Mechinal&#xff09;&#xff1a;Java虚拟机 &#xff08;1&#xff09;JDK和JRE 是…

Python海龟画图 几种基本图形

注&#xff1a;本文主要根据绘制步骤进行区分&#xff0c;实际使用时应当调节参数以绘制需要的图形。文中的步骤均为循环进行&#xff0c;循环50到100次&#xff0c;具体次数见代码示例。 1.前进小角度旋转 绘制效果如图&#xff0c;如果旋转角度为360的因数则绘制出多边形。 …

OJ Summation of Four Primes

1.题目 题目描述 Euler proved in one of his classic theorems that prime numbers are infinite in number. But can every number be expressed as a summation of four positive primes? I don’t know the answer. May be you can help!!! I want your solution to be v…

弹性盒子(display: flex)布局超全讲解|Flex 布局教程

文章目录 什么是弹性布局&#xff1f;弹性布局的特点&#xff1f;容器的属性justify-contentalign-itemsflex-directionflex-wrapflex-flowalign-contentorder属性flex-grow属性flex-shrink属性flex-basis属性flex属性align-self属性 什么是弹性布局&#xff1f; 弹性布局&…

我被今年就业难度震惊到了

随着毕业季到来&#xff0c;今年高校毕业生就业问题正在被越来越多的人关注。年年都是最难就业季&#xff0c;但今年却格外不同寻常的难。大家都知道 2022 年毕业生人数历史上首次突破千万。而今年毕业生人数&#xff0c;高达 1158 万人&#xff0c;史无前例的多。加上海外留学…

【Unity Shader】从入门到着魔(2)用C#画一个立方体

文章目录 一、构成一个立方需要多少个顶点?二、定义三角面的索引数组:三、定义UV坐标数组:四、最后构建Mesh:五、完整代码:一、构成一个立方需要多少个顶点? 这个问题是面试经常被问到的题。如上图,我们知道在几何中立方体有6个面,8个顶点。但在图形学中,顶点指的是模…