当前位置: 首页 > news >正文

加强门户网站建设通知外贸推广

加强门户网站建设通知,外贸推广,wordpress 好慢哪,公共资源交易中心职能C/C杂谈-printf的可变参数机制 文章目录 C/C杂谈-printf的可变参数机制printf的使用printf的源码源码剖析 多参数实现机制原理 C11引入了可变参数模板机制,对模板参数进行了高度泛化,但是对于可变参数其实C语言学习中早已遇到过,那就是printf…

C/C++杂谈-printf的可变参数机制

文章目录

  • C/C++杂谈-printf的可变参数机制
    • printf的使用
    • printf的源码
      • 源码剖析
    • 多参数实现机制原理

C++11引入了可变参数模板机制,对模板参数进行了高度泛化,但是对于可变参数其实C语言学习中早已遇到过,那就是printf可以进行多参数的输出,这是怎么实现的呢?

printf的使用

我们对于printf的用法无非两种

    const char *str = "hello , world\n";printf(str);//直接传入字符串地址int year = 2023;printf("%d%s", year, "原神启动");//传入格式控制字符串地址和参数

我们printf的参数是先是一个字符串,后面才是我们的输出变量,可以嗅出printf对于多参数的控制应该和传入的第一个字符串有关,那么究竟是如何实现的呢?

printf的源码

//acenv.h
typedef char *va_list;
#define  _AUPBND        (sizeof (acpi_native_int) - 1)
#define  _ADNBND        (sizeof (acpi_native_int) - 1)#define _bnd(X, bnd)    (((sizeof (X)) + (bnd)) & (~(bnd)))
#define va_arg(ap, T)   (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
#define va_end(ap)      (void) 0
#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
//start.c
static char sprint_buf[1024];
int printf(char *fmt, ...)//格式控制字符串和C的函数多参数
{va_list args;//va_list就是char * 的typedefint n;va_start(args, fmt);n = vsprintf(sprint_buf, fmt, args);va_end(args);write(stdout, sprint_buf, n);return n;
}
//unistd.h
static inline long write(int fd, const char *buf, off_t count)
{return sys_write(fd, buf, count);
}

源码剖析

映入眼帘的就是一串宏定义

看我们printf的函数参数部分,char *fmt就是我们的格式控制字符串,后面的…是C的函数多参数,即后面的参数数目不定

va_list就是char * 的typedef,也就是定义了名为args的char指针

va_start(args, fmt);就是把args指向fmt后面的第一个参数的地址

这里对va_start进行解释

#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))

可见ap指向的是A地址往后偏移_bnd字节,而 _bnd 传参了 _ADNBND,_ADNBND = (sizeof (acpi_native_int) - 1)

typedef s32 acpi_native_int 若采用这种宏定义,表明int 类型是用32位表示,也表示当前内存是4字节对齐

acpi_native_int这个参数是平台相关的

所以sizeof (acpi_native_int)是当前平台的int大小,我们假设是4字节,那么_ADNBND就是3

#define _bnd(char,3)    ==>  (1+3)&(~3)  ==> 4#define _bnd(int,3)     ==>  (4+3)&(~3)  ==> 4#define _bnd(double,3)  ==>  (4+3)&(~3)  ==> 8

我们通过上述样例可以明白**_bnd就是获取类型A的内存对齐大小**,假如32位平台那么就是4的倍数

所以va_start(args, fmt) 就是把fmt偏移char*内存对齐大小个字节然后赋值给args,这样args指向的就是格式字符串后面的参数

n = vsprintf(sprint_buf, fmt, args);这里的n则是我们实际控制输出的字符数,我们printf实际就是一个输出字符的函数,n也是我们的返回值

而后面的 write(stdout, sprint_buf, n);无非就是把缓冲区里的n个字符输出到stdout输出流,这就不是我们讨论的重点了

多参数实现机制原理

通过上面的剖析,我们发现printf由格式控制字符串得到下一个参数的起始地址,而下一个起始地址是fmt地址偏移内存对齐大小个字节

这是为什么呢?

这跟函数的压栈顺序有关。我们C/C++默认__cdel的从右至左将参数压栈,而我们栈是向下增长的,所以先入栈的地址高,后入栈的地址低,所以格式字符串的地址最低,往上偏移自然能得到其他参数的地址

void func(int a, int b, int c)
{printf("a = %d located [%x]\n", a, &a);printf("b = %d located [%x]\n", b, &b);printf("c = %d located [%x]\n", c, &c);
}
signed main()
{func(1, 2, 3);return 0;
}
//输出
a = 1 located [b3bff960]
b = 2 located [b3bff968]
c = 3 located [b3bff970]

得到地址后,由于我们规定格式控制字符串中%的数量即为输出参数数量,然后就能拿到所有参数放到缓冲区,再输出到标准输出流

如果我们想要实现多参数机制(需要了解<stdarg.h>),自然也要通过我们的参数设定模式,类似格式控制中百分号的数量来确定参数的数目,而名称出现的顺序对应参数的顺序。

可见C语言的多参数机制是很繁琐的,而我们C++11引入可变参数模板也正是为了追求更好的参数泛化。

http://www.ritt.cn/news/5739.html

相关文章:

  • 家装设计师工资高吗seo推广seo技术培训
  • 东莞网站建设建网站全球搜怎么样
  • 专业做网站公司排名在哪里可以做百度推广
  • 网站制作青岛免费软文推广平台都有哪些
  • 沈阳做网站优化搜索引擎排名2022
  • 做网站可以用中文域名备案嘛优化器
  • 做网站可以申请专利吗刷粉网站推广马上刷
  • 各种浏览器网站大全艺术培训学校招生方案
  • 网站seo专员招聘windows优化大师要钱
  • 英文b2b网站系统网络营销渠道策略研究
  • 网站开发职位描述百度竞价推广收费标准
  • 书店商城网站html模板下载抖音代运营公司
  • jquery 动画网站网页设计制作网站模板
  • 商洛市住房和城乡建设局网站手机优化大师
  • 东莞网站系统哪里好手游推广平台哪个好
  • 网络运维网站在线查询网站收录
  • 有那些专门做财务分析的网站搜索关键词的网站
  • 怎么做 社区网站seo优化网站推广专员招聘
  • 房产网站设计模板网站推广在哪好
  • 网站怎么做吸引人百度手机助手应用商店下载
  • 免费crm网站下载苏州seo排名优化课程
  • 小程序后端怎么开发合肥网站seo推广
  • 深圳手机网站开发免费企业建站
  • 软文营销的概念是什么杭州专业seo服务公司
  • 网站建设与规划论文app拉新推广
  • 网站开通支付宝支付seo的主要工作内容
  • 网站例子大全小程序开发公司前十名
  • 上海做网站的费用全球十大搜索引擎入口
  • 在什么平台可以接外包客服杭州seo搜索引擎优化公司
  • 做网站 赚钱多吗如何推广自己产品