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 函数,并传递了一个格式化字符串和两个参数。


目录
相关文章
|
1月前
|
Linux
关于Linux目录访问函数总结
关于Linux目录访问函数总结
13 1
|
21小时前
|
Linux
linux中wait与waitpid函数使用场景及扩展
linux中wait与waitpid函数使用场景及扩展
|
21小时前
|
Linux
linux中fork函数与vfork函数的区别
linux中fork函数与vfork函数的区别
|
2天前
|
消息中间件 存储 Linux
linux实时应用如何printf输出不影响实时性?
本文探讨了Linux实时任务中为何不能直接使用`printf(3)`,并介绍了实现不影响实时性的解决方案。实时任务的执行时间必须确定且短,但`printf(3)`的延迟取决于多个因素,包括用户态glibc缓冲、内核态TTY驱动和硬件。为确保实时性,通常将非实时IO操作交给低优先级任务处理,通过实时进程间通信传递信息。然而,即使这样,`printf(3)`在glibc中的实现仍可能导致高优先级任务阻塞。Xenomai 3提供了一个实时的`printf()`实现,通过libcobalt库在应用编译链接时自动处理,预分配内存,使用共享内存和线程特有数据来提高效率和实时性。
12 0
linux实时应用如何printf输出不影响实时性?
|
4天前
|
存储 算法 网络协议
【探索Linux】P.26(网络编程套接字基本概念—— socket编程接口 | socket编程接口相关函数详细介绍 )
【探索Linux】P.26(网络编程套接字基本概念—— socket编程接口 | socket编程接口相关函数详细介绍 )
12 0
|
5天前
|
消息中间件 Unix Linux
【探索Linux】P.14(进程间通信 | 匿名管道 | |进程池 | pipe() 函数 | mkfifo() 函数)
【探索Linux】P.14(进程间通信 | 匿名管道 | |进程池 | pipe() 函数 | mkfifo() 函数)
13 0
|
5天前
|
Linux Shell
Linux中system函数
Linux中system函数
8 0
|
10天前
|
Linux Shell 调度
【Linux系列】fork( )函数原理与应用详解——了解【父子进程及其特性】(代码演示,画图帮助理解,思维导图,精简)(11)
【Linux系列】fork( )函数原理与应用详解——了解【父子进程及其特性】(代码演示,画图帮助理解,思维导图,精简)(11)
|
18天前
|
算法 Linux Shell
【linux进程(二)】如何创建子进程?--fork函数深度剖析
【linux进程(二)】如何创建子进程?--fork函数深度剖析
|
1月前
|
Linux 开发者
Linux文件编程(open read write close函数)
通过这些函数,开发者可以在Linux环境下进行文件的读取、写入和管理。 买CN2云服务器,免备案服务器,高防服务器,就选蓝易云。百度搜索:蓝易云
94 4