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

百度网页版下载网站如何做seo推广方案

百度网页版下载,网站如何做seo推广方案,网站注册管理策划方案,云南住建局和城乡建设报考网站作者#xff1a;戎亚新 摘要#xff1a;一直以来都觉得printf似乎是c语言库中功能最强大的函数之一#xff0c;不仅因为它能格式化输出#xff0c;更在于它的参数个数没有限制#xff0c;要几个就给几个#xff0c;来者不拒。printf这种对参数个数和参数类型的强大适应性…作者戎亚新 摘要一直以来都觉得printf似乎是c语言库中功能最强大的函数之一不仅因为它能格式化输出更在于它的参数个数没有限制要几个就给几个来者不拒。printf这种对参数个数和参数类型的强大适应性让人产生了对它进行探索的浓厚兴趣。 关键字printf, 可变参数 1. 使用情形 int a 10; double b 20.0; char *str Hello world; printf(begin print\n); printf(a%d, b%.3f, str%s\n, a, b, str); ... 从printf的使用情况来看我们不难发现一个规律就是无论其可变的参数有多少个printf的第一个参数总是一个字符串。而正是这第一个参数使得它可以确认后面还有有多少个参数尾随。而尾随的每个参数占用的栈空间大小又是通过第一个格式字符串确定的。然而printf到底是怎样取第一个参数后面的参数值的呢请看如下代码 2. 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, ...) { va_list args; int 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); } 3. 分析 从上面的代码来看printf似乎并不复杂它通过一个宏va_start把所有的可变参数放到了由args指向的一块内存中然后再调用vsprintf. 真正的参数个数以及格式的确定是在vsprintf搞定的了。由于vsprintf的代码比较复杂也不是我们这里要讨论的重点所以下面就不再列出了。我们这里要讨论的重点是va_start(ap, A)宏的实现它对定位从参数A后面的参数有重大的制导意义。现在把 #define va_start(ap, A) (void) ((ap) (((char *) (A)) (_bnd (A,_AUPBND)))) 的含义解释一下如下 va_start(ap, A) { char *ap ((char *)(A)) sizeof(A)并int类型大小地址对齐 } 在printf的va_start(args, fmt)中fmt的类型为char *, 因此对于一个32为系统 sizeof(char *) 4, 如果int大小也是32则va_start(args, fmt);相当于 char *args (char *)(fmt) 4; 此时args的值正好为fmt后第一个参数的地址。对于如下的可变参数函数void fun(double d,...) { va_list args; int n; va_start(args, d); } 则 va_start(args, d);相当于char *args (char *)d sizeof(double); 此时args正好指向d后面的第一个参数。 可变参数函数的实现与函数调用的栈结构有关正常情况下c/c的函数参数入栈规则为__stdcall, 它是从右到左的即函数中的最右边的参数最先入栈。对于函数 void fun(int a, int b, int c) { int d; ... } 其栈结构为0x1ffc--d 0x2000--a 0x2004--b 0x2008--c 对于任何编译器每个栈单元的大小都是sizeof(int), 而函数的每个参数都至少要占一个栈单元大小如函数 void fun1(char a, int b, double c, short d) 对一个32的系统其栈的结构就是0x1ffc--a (4字节) 0x2000--b (4字节) 0x2004--c (8字节) 0x200c--d (4字节) 对于函数void fun1(char a, int b, double c, short d) 如果知道了参数a的地址则要取后续参数的值则可以通过a的地址计算a后面参数的地址然后取对应的值而后面参数的个数可以直接由变量a指定当然也可以像printf一样根据第一个参数中的%模式个数来决定后续参数的个数和类型。如果参数的个数由第一个参数a直接决定则后续参数的类型如果没有变化并且是已知的则我们可以这样来取后续参数, 假定后续参数的类型都是double; void fun1(int num, ...) { double *p (double *)((num)1); double Param1 *p; double Param2 *(p1); ... double Paramn *(pnum); } 如果后续参数的类型是变化而且是未知的则必须通过一个参数中设定模式来匹配后续参数的个数和类型就像printf一样当然我们可以定义自己的模式如可以用i表示int参数d表示double参数为了简单我们用一个字符表示一个参数并由该字符的名称决定参数的类型而字符的出现的顺序也表示后续参数的顺序。 我们可以这样定义字符和参数类型的映射表 i---int s---signed short l---long c---char ild模式用于表示后续有三个参数按顺序分别为int, long, double类型的三个参数那么这样我们可以定义自己版本的printf 如下 void printf(char *fmt, ...) { char s[80] ; int paramCount strlen(fmt); write(stdout, paramCount , strlen(paramCount )); itoa(paramCount,s,10); write(stdout, s, strlen(s)); char *p (char *)(fmt) sizeof(char *); int *pi (int *)p; for (int i0; iparamCount; i) { char line[80] ; strcpy(line, param); itoa(i1, s, 10); strcat(line, s); strcat(line, ); switch(fmt[i]) { case i: case s: itoa((*pi),s,10); strcat(line, s); pi; break; case c: { int len strlen(line); line[len] (char)(*pi); line[len1] \0; } break; case l: ltoa((*(long *)pi),s,10); strcat(line, s); pi; break; default: break; } } } 也可以这样定义我们的Max函数它返回多个输入整型参数的最大值 int Max(int n, ...) { int *p n 1; int ret *p; for (int i0; in; i) { if (ret *(p i)) ret *(p i); } return ret; } 可以这样调用, 后续参数的个数由第一个参数指定 int m Max(3, 45, 12, 56); int m Max(1, 3); int m Max(2, 23, 45); int first 34, second 45, third5; int m Max(5, first, second, third, 100, 4); 结论 对于可变参数函数的调用有一点需要注意实际的可变参数的个数必须比前面模式指定的个数要多或者不小于 也即后续参数多一点不要紧但不能少 如果少了则会访问到函数参数以外的堆栈区域这可能会把程序搞崩掉。前面模式的类型和后面实际参数的类型不匹配也有可能造成把程序搞崩溃只要模式指定的数据长度大于后续参数长度则这种情况就会发生。如 printf(%.3f, %.3f, %.6e, 1, 2, 3, 4); 参数1234的默认类型为整型而模式指定的需要为double型其数据长度比int大这种情况就有可能访问函数参数堆栈以外的区域从而造成危险。但是printf(%d, %d, %d, 1.0, 20., 3.0);这种情况虽然结果可能不正确但是确不会造成灾难性后果。因为实际指定的参数长度比要求的参数长度长堆栈不会越界。
http://www.zqtcl.cn/news/804770/

相关文章:

  • 天津网站建设zhy88宁波企业黄页公司黄页
  • 个人网站课程设计报告app免费制作软件中文版
  • 品牌建设网站规划盛唐网站建设
  • 商城网站系统建站平台上建设的网站可以融资吗
  • 怎么查网站空间wordpress快速入门
  • 长沙 网站运营德国服务器网站
  • 有动效网站建网站的书籍
  • 网站模版更新公告2023年ppt模板免费
  • 广饶网站建设北京建设工程监督网站
  • 长沙网站建设电话郑州网站空间
  • 做网站是怎样赚钱的网页制作工具按其制作方式有
  • 网站地图在哪里展现电子商务网站需要做那些准备工作
  • 深圳网站设计收费标准中端网站建设公司
  • 有关wordpress教学的网站wordpress返回旧版
  • php做网站弊端wordpress强大播放器
  • 怎么直接做免费网站wordpress如何自建站
  • 中国建设银行建银购网站金堂企业网站建设
  • 手机微网站开发的目的和意义温州公司网站开发
  • 除了外链 还有什么办法使网站提高排名网站建设珠海 新盈科技
  • 几分钟弄清楚php做网站中国风景摄影网
  • 卡片式网站网页设计公司的市场评估
  • 网站开发的感想wordpress水煮鱼
  • 网站开发入门培训机构自豪地采用wordpress更改
  • 手机网站来几个最近的国际新闻大事件
  • 重庆网站开发设计公司电话资源网站优化排名
  • 国土分局网站建设方案外贸seo网站
  • 营销型网站建设易网拓烟台h5网站建设公司
  • PHP网站开发都需要学什么中介网站模板
  • 网站建设与维护模板官方网站建设费用应入什么科目
  • 网站建设企业关键词seo关键词库