详解 printf() 函数
声明(叠甲):鄙人水平有限,本文章仅供参考。
1. 引子
#include <stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
上面这一段代码大家应该都十分的熟悉,这是我们学习 C 语言时接触到的第一段代码,但问到printf这个函数是如何工作运行的、是怎么做到可变参数传递的,却没多少人能回答上来,因此我想写下这篇文章来分享下我对 printf 的认识,但是因鄙人水平有限,本文只会粗略的进行介绍。
2.可变参数传递
printf 的实现其实是十分的复杂的,我们一步一步来进行说明,首先我们来看看 printf 是如何做到可变参数传递的,即如下代码
#include <stdio.h>
int main()
{
printf("hello world\n");
printf("hello %s\n","world");
printf("%s %s\n","hello","world");
return 0;
}
我们可以看到 printf 传递的参数是可以变的,是不固定,这与我们平时接触到的的函数参数传递有亿点点的不同。
为明白这个,我先进行一波 RTFSC(看源代码)
_Check_return_opt_
_CRT_STDIO_INLINE int __CRTDECL printf(
_In_z_ _Printf_format_string_ char const* const _Format,
...);
通过代码跳转,我们可以在 stdio.h 这个文件中看到 printf 的定义,但是看起有点复杂,充满了我们不太熟悉的宏定义。为了不理会不我们不感兴趣的部分,在此我对其进行一波简化,如下
int printf(char *Format,...);
这样是不是简单多了,跟我们平时写的函数是不是很很像,返回值类型是 int ,传入参数是一个 char 的指针 Format 和一个 ... 。其中 ... 就是实现可变参数的所在之处,其具体用法和含义,因本人水平有限可能说不明白(像偷懒,就在此扔个教学链接吧。
3.printf 的内部
printf 的实现真的十分复杂,在此就以阉割版为例了。
在第二节后,我们明白了可变参数传递的具体实现原理。这节,我们就来看看 printf 是如何利用它来工作的,如下:
#include <stdarg.h>
int printf(const char *fmt, ...)
{
va_list list;
va_start(list,fmt);
int ret_num = 0;
for(;fmt[ret_num] != '\0';ret_num++)
{
switch (fmt[ret_num])
{
case '%':
ret_num++;
switch (fmt[ret_num])
{
case 'c':
Argchar = va_arg(list,int);
putch(Argchar);
break;
default:
ret_num--;
break;
}
break;
default:
putch(fmt[ret_num]);
break;
}
}
return ret_num;
}
int main()
{
printf("char = %c\n",'C');
return 0;
}
这是一个阉割版的 printf,只能实现 %c 的传递,但是不凡我们以此为突破口来弄得 printf 的具体实现。
如上,我们先来看看它的返回值,int 类型,大小为传递参数的个数。对于传入参数,先是对于不同的格式化字符串进行判断(即 %d %c那些,具体各个含义可以通过 man3 printf 这个命令来查看手册的描述),再使用 putch 这个函数进行单个字符的输出,而 putch 的实现就是后话了。
4.结束语
好了,对于 printf 的介绍就到这了,相信你对于 printf 的也有了进一步的了解,要不要自己写个 printf 来玩玩?但是记得按照手册的描述来!
详解 printf() 函数的更多相关文章
- LESS详解之函数(四)
之前已经为大家介绍了一些LESS函数,大家应该对之前介绍的有所了解了.下面依旧为大家介绍LESS的函数,附加着一些小例子.希望这些有关LESS的函数能在大家编写LESS的时候有所帮助. saturat ...
- 详解 $_SERVER 函数中QUERY_STRING和REQUEST_URI区别
详解 $_SERVER 函数中QUERY_STRING和REQUEST_URI区别 http://blog.sina.com.cn/s/blog_686999de0100jgda.html 实例: ...
- ViewPager 详解(二)---详解四大函数
前言:上篇中我们讲解了如何快速实现了一个滑动页面,但问题在于,PageAdapter必须要重写的四个函数,它们都各有什么意义,在上节的函数内部为什么要这么实现,下面我们就结合Android的API说明 ...
- 详解JMeter函数和变量(转载)
详解JMeter函数和变量(1) JMeter函数可以被认为是某种特殊的变量,它们可以被采样器或者其他测试元件所引用.函数调用的语法如下: ${__functionName(var1,var2,var ...
- 详解python函数的参数
详解python函数的参数 一.参数的定义 1.函数的参数在哪里定义 在python中定义函数的时候,函数名后面的括号里就是用来定义参数的,如果有多个参数的话,那么参数之间直接用逗号, 隔开 案列: ...
- 详解Python函数参数定义及传参(必备参数、关键字参数、默认可省略参数、可变不定长参数、*args、**kwargs)
详解Python函数参数定义及传参(必备参数.关键字参数.默认可省略参数.可变不定长参数.*args.**kwargs) Python函数参数传参的种类 Python中函数参数定义及调用函数时传参 ...
- C++学习45 流成员函数put输出单个字符 cin输入流详解 get()函数读入一个字符
在程序中一般用cout和插入运算符“<<”实现输出,cout流在内存中有相应的缓冲区.有时用户还有特殊的输出要求,例如只输出一个字符.ostream类除了提供上面介绍过的用于格式控制的成员 ...
- Knowledge Point 20180303 详解main函数
学习Java的朋友想来都是从HelloWorld学起的,那么想来都对main函数不陌生了,但是main函数究竟是怎么回事呢?main函数中的参数是做什么的呢?main函数为什么能作为程序的入口呢?可不 ...
- 详解 pthread_detach()函数
pthread_t 类型定义: typedef unsigned long int pthread_t; //come from /usr/include/bits/pthread.h 用途:pthr ...
- 详解calc()函数功能
calc()对大家来说,或许很陌生,不太会相信calc()是css中的部分.因为看其外表像个函数,既然是函数为何又出现在CSS中呢?这一点也让我百思不得其解,今天有一同事告诉我,说CSS3中有一个属性 ...
随机推荐
- noi 1.1 3 对齐输出
描述 输入三个整数,按每个整数占8个字符的宽度,右对齐输出它们. 输入 只有一行,包含三个整数,整数之间以一个空格分开. 输出 只有一行,按照格式要求依次输出三个整数,之间以一个空格分开. 样例输入 ...
- git合并指定分支的commit到主干上
1.先切换分支到master git checkout master 2.目前正处于主干上,执行命令,将分支从最后一个commit合并到主干上 git rebase --onto cb4023015f ...
- Java中String,JSON对象,java实体类(Bean)之间的相互转换
FastJson对于json格式字符串的解析主要用到了一下三个类: (1)JSON:fastJson的解析器,用于JSON格式字符串与JSON对象及javaBean之间的转换. (2)JSONObje ...
- OpenCV 4.5.2环境配置 + 图片灰度化处理
一,OpenCV环境配置 注意:以下配置内容为Android开发环境配置好的基础上的OpenCV配置环境 1.官网下载OpenCV的sdk包,下载的是4.5.2的Android版本 Releases ...
- nuxt中asyncData和fetch的区别
asyncData作用于页面pages,在组件中不能使用,并且asyncData中没有this,如果想要给data中的数据赋值,要在asyncData函数中return出去 fetch 作用于组件中c ...
- spring security添加接口白名单
在项目中遇到的问题是要将某个接口设为白名单,无需验证即可被用户使用. 解决方法: 在nacos配置文件中ignore whites(不校验白名单)中添加对应接口,无gateway前缀即可,添加立即生效 ...
- sqlserver substring 函数截取text格式文本格式乱码导致的定位错误的问题
描述:使用 charindex 函数对 text 字段所要截取的内容下标读取例如:str(表字段名称-类型text)= <p>●123456</p> 截取 123 , inde ...
- hdu:"红色病毒"问题(指数型母函数用e^x指数函数来计算)
Problem Description医学界发现的新病毒因其蔓延速度和Internet上传播的"红色病毒"不相上下,被称为"红色病毒",经研究发现,该病毒及其变 ...
- Python笔记(4)——元组(Python编程:从入门到实践)
元组 1. 元组:不可变的列表.元组一经创建不能被修改. 2. 表示:用圆括号()来表示,并用逗号来分隔其中的元素.可通过索引访问其元素. 3. 访问:访问列表元素,指出元组的名称,再指出元素的索引, ...
- JAVA 学习打卡 day3
2022-04-25 22:53:16 1.运算符 表达式是由操作数与运算符所组成Java中的语句有很多种形式,表达式就是其中一种形式.表达式是由操作数与运算符所组成,操作数可以是常量.变量也可以是方 ...