详解 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中有一个属性 ...
随机推荐
- 命令提示符怎么打开和Dos命令的基本使用
Dos命令 Dos命令窗口我们可以通过win+R输入cmd来打开 如果要用管理员身份打开直接在开始里搜索命令提示符,以管理员身份打开! 一些简单的Dos命令 //切换盘符 盘符名: //进入 cd / ...
- 策略模式demo
/** StrategyContext. */ public class StrategyContext { private Strategy strategy; // 传入的是Strategy的实现 ...
- 简单a+b
1 # include <stdio.h> 2 3 /*输入两个整数a和b,计算a+b的和 4 注意此题是多组测试数据 */ 5 6 // 我的解法 7 void main(){ 8 in ...
- app自动化前置准备&环境搭建
编写脚本之前的一些前置准备工作. 1,安装appium server:官网地址:http://appium.io/ 安装教程:https://www.cnblogs.com/gancuimian/p/ ...
- pytest之conftest.py
一.conftest.py的特点 1.可以跨.py文件调用,有多个.py文件调用时,可让conftest.py只调用了一次fixture,或调用多次fixture 2.conftest.py与运行的用 ...
- Vue中nextTick的时序问题
前言 Vue.$nextTick这个API相信很多人都用过,按照文档的解释,"在下次DOM更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的DOM".我们通 ...
- Jetlinks物联网基础平台 前端运行项目遇到的问题
电脑中的环境要必备 node.js和yarn(需要将他们都添加到环境变量中,否则会报错) 1.在github上面拉取代码 $ git clone https://github.com/jetlinks ...
- JS笔记(三):函数与对象
镇楼图 Pixiv:torino 四.Function类型 Rest语法 一些函数如Math.max可以支持任意数量的参数,JS中对于这样的参数可以简单使用...来实现,使用剩余参数,它支持收集剩余的 ...
- Verilog 变量声明与数据类型一
Verilog 变量声明与数据类型一 Verilog语法中最基本的数据类型有 线网(wire),寄存器(reg)和整数(integer)三种类型,这三种数据类型是可综合的数据类型,在Verilog 程 ...
- if判断while循环