Linux下实现自己的printf函数

简介: Linux下实现自己的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 函数,并传递了一个格式化字符串和两个参数。


相关实践学习
CentOS 7迁移Anolis OS 7
龙蜥操作系统Anolis OS的体验。Anolis OS 7生态上和依赖管理上保持跟CentOS 7.x兼容,一键式迁移脚本centos2anolis.py。本文为您介绍如何通过AOMS迁移工具实现CentOS 7.x到Anolis OS 7的迁移。
目录
相关文章
|
3月前
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
148 6
|
3月前
|
Linux Shell
Linux系统编程:掌握popen函数的使用
记得在使用完 `popen`打开的流后,总是使用 `pclose`来正确关闭它,并回收资源。这种做法符合良好的编程习惯,有助于保持程序的健壮性和稳定性。
160 3
|
3月前
|
Linux
在Linux内核中根据函数指针输出函数名称
在Linux内核中根据函数指针输出函数名称
|
4月前
|
Linux PHP
Linux CentOS 宝塔 Suhosin禁用php5.6版本eval函数详细图文教程
【8月更文挑战第27天】本文介绍两种禁用PHP执行的方法:使用`PHP_diseval_extension`禁用和通过`suhosin`禁用。由于`suhosin`不支持PHP8,仅适用于PHP7及以下版本,若服务器安装了PHP5.6,则需对应安装`suhosin-0.9.38`版本。文章提供了详细的安装步骤,并强调了宝塔环境下与普通环境下的PHP路径差异。安装完成后,在`php.ini`中添加`suhosin.so`扩展并设置`executor.disable_eval = on`以禁用执行功能。最后通过测试代码验证是否成功禁用,并重启`php-fpm`服务生效。
55 2
|
4月前
|
Shell Linux C语言
Linux0.11 execve函数(六)
Linux0.11 execve函数(六)
79 1
|
4月前
|
Linux API
Linux源码阅读笔记07-进程管理4大常用API函数
Linux源码阅读笔记07-进程管理4大常用API函数
|
4月前
|
Linux
Linux0.11 文件打开open函数(五)
Linux0.11 文件打开open函数(五)
50 0
|
4月前
|
存储 Linux 调度
Linux 0.11 fork 函数(二)
Linux 0.11 fork 函数(二)
52 0
|
4月前
|
Shell Linux 程序员
在Linux中, 什么是shell函数?如何使用它们?
在Linux中, 什么是shell函数?如何使用它们?
|
4月前
|
小程序 Linux 开发者
Linux之缓冲区与C库IO函数简单模拟
通过上述编程实例,可以对Linux系统中缓冲区和C库IO函数如何提高文件读写效率有了一个基本的了解。开发者需要根据应用程序的具体需求来选择合适的IO策略。
37 0