【C/C++开发】C语言实现函数可变参数

       函数原型: int printf(const char *format[,argument]...)
       返 回 值: 成功则返回实际输出的字符数,失败返回-1.
 函数说明:
       在printf()函数中,format后面的参数个数不确定,且类型也不确定,这些参数都存放在栈内.调用printf()函数时,根据format里的格式("%d %f...")依次将栈里参数取出.而取出动作要用到va_arg、va_end、va_start这三个宏定义,再加上va_list.
     (1)va_list事实上是一char *类型,即:
            typedef char* va_list;
     (2)三个宏定义:
            #define _INTSIZEOF(n)    ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) 
            #define va_start(ap,v)     ( ap = (va_list)&v + _INTSIZEOF(v) ) 
            #define va_arg(ap,type)  ( *(type *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) 
            #define va_end(ap)          ( ap = (va_list)0 ) 
   【attention】C语言中可变参数的原理---printf()函数 
            int printf(const char* format,...);   
      使用过C语言的人所再熟悉不过的printf函数原型,它的参数中就有固定参数format和可变参数(用”…”表示).而程序员又可以用各种方式来调用printf,如: 
            printf("%d ",value);   
            printf("%s ",str);   

            printf("the number is %d,string is:%s ",value,str); 
       可以看出,该函数的参数格式不固定,参数类型不固定.在C语言中使用宏来处理这些可变参数.这些宏看起来很复杂,其实原理挺简单,即根据参数入栈的特点从最靠近第一个可变参数的固定参数开始,依次获取每个可变参数的地址.
 (1)宏va_start
      通过该宏定义可以获取到可变参数表的首地址,并将该地址赋给指针ap.
 (2)宏va_arg
      通过该宏定义可以获取当前ap所指向的可变参数,并将指针ap指向下一个可变参数.注意,该宏的第二个参数为类型.
 (3)宏va_end
      通过该宏定义可以结束可变参数的获取.


      程序员通过这三个宏定义就可以实现对可变参数的处理.例如:


   #include <stdio.h>  
  
typedef char* va_list;   
   #define _INTSIZEOF(n)    ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )   
   #define va_start(ap,v)   ( ap = (va_list)&v + _INTSIZEOF(v) )   
   #define va_arg(ap,type)  ( *(type *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )   
   #define va_end(ap)       ( ap = (va_list)0 )   
  
int cal_val(int c, ...)   
{   
    int sum = c;   
    va_list ap;              //声明指向char型的指针  
    va_start(ap,c);          //获取可变参数列表的首地址,并赋给指针ap  
  
    c = va_arg(ap,int);      //从可变参数列表中获取到第一个参数(返回值即为参数)  
    while(0 != c)   
    {   
        sum += c;   
        c = va_arg(ap,int);  //循环的从可变参数列表中获取到参数(返回值即为参数)  
    }  
    va_end(ap);              //结束从可变参数列表中获取参数  
    return sum;   
}    
   
int main(int argc, char* argv[])   
{   
    int value1;  
      
    value1 = cal_val(1,2,3,4,5,6,7,8,9,0);   
    printf("value1=%d/n",value1);  
    value2 = cal_val(6,7,8,9,0);   
    printf("value2=%d/n",value2);  
      
    return 0;   
}   


转载于:https://www.cnblogs.com/huty/p/8517288.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/372781.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java postgresql json_java – 将PostgreSQL JSON列映射到Hibernate值类...

See PgJDBC bug #265.PostgreSQL对数据类型转换过于严格,非常严格.它不会隐式地将文本转换为类似文本的值,例如xml和json.解决此问题的严格正确方法是编写使用JDBC setObject方法的自定义Hibernate映射类型.这可能有点麻烦,所以你可能只想通过创建一个较弱的强制转换来使Postgr…

面向接口编程详解(三)——模式研究

通过前面两篇&#xff0c;我想各位朋友对“面向接口编程”的思想有了一定认识&#xff0c;并通过第二篇的例子&#xff0c;获得了一定的直观印象。但是&#xff0c;第二篇中的例子旨在展示面向接口编程的实现方法&#xff0c;比较简单&#xff0c;不能体现出面向接口编程的优势…

错误学习:Java + OSGi

最近&#xff0c;我致力于在OSGi环境中使Apache Hive工作。 虽然没有被证明是小菜一碟&#xff08;软件对吗&#xff1f;。。为什么我不感到惊讶&#xff1f; &#xff09;&#xff0c;它引导我解决了各种Java和OSGi错误。 在这里&#xff0c;我列出了其中一些让我有些吃力的东…

iOS多Targets管理

序言&#xff1a; 个人不善于写东西&#xff0c;就直奔主题了。 其实今天会注意到多targets这个东西&#xff0c;是因为在学习一个第三方库FBMemoryProfiler的时候&#xff0c;用到了&#xff0c;所以就搜索了一些相关资料&#xff0c;就在这里记录一下。 可能每个人都会遇到这…

优化的34条定律

1.Minimize HTTP Requests 减少HTTP请求 图片、css、script、flash等等这些都会增加http请求数&#xff0c;减少这些元素的数量就能减少响应时间。把多个JS、CSS在可能的情况下写进一个文件&#xff0c;页面里直接写入图片也是不好的做法&#xff0c;应该写进CSS里&#xff0c;…

休眠提示:排序和排序

让我们介绍另一个休眠性能提示。 你还记得以前的休眠的模式后 &#xff1f; 我们有一个与一对多协会有关的星际飞船和军官。 Entity public class Starship {Id GeneratedValue(strategyGenerationType.SEQUENCE) private Long id;public Long getId() {return id;}protected v…

java 基本类型 线程安全_java的基本类型和i++线程安全性的深入解析

在java中&#xff0c;除了long和double的8个字节、64位比特的变量外&#xff0c;其他的基本变量都是原子性的。java存储模型要求获取和存储操作都为原子性&#xff0c;但是对于非volatile的long和double变量&#xff0c;jvm允许将64位的读或写划分为两个32位的操作。如果读和写…

MySQL配置文件mysql.ini参数详解

my.ini&#xff08;Linux系统下是my.cnf&#xff09;&#xff0c;当mysql服务器启动时它会读取这个文件&#xff0c;设置相关的运行环境参数。 my.ini分为两块&#xff1a;Client Section和Server Section。 Client Section用来配置MySQL客户端参数。 要查看配置参数可以用下面…

微信公众平台和微信开放平台的区别

自己也刚开始做微信开发&#xff0c;先写写自己的认识&#xff1a; 用微信公众平台可以做手机端H5页面的微信登录&#xff0c;微信支付 用微信开放平台可以做PC端网页的微信登录。 转载于:https://www.cnblogs.com/mafeng/p/5610770.html

java 传递bean_如何将bean作为参数传递给JSP标记?

我ve created a custom JSP tag that is supposed to accept a list of products to render, but I我无法弄清楚如何将列表传递给标签 . 产品列表作为页面范围的bean存在 . Web应用程序使用Struts taglib在Struts 1.2.x中编写 .这是我的代码的简化版本&#xff1a;renderProduc…

Business Component(BC)和Business Object(BO)

Siebel应用架构的一个成功的地方就是在应用里引入了BC&#xff0c;BO的概念&#xff0c;从而使得几千张关系数据表能够按照业务的含义组织成业务对象&#xff0c;对于业务人员而言具有了业务上的含义&#xff0c;而不仅仅是从技术人员的观点来对待数据&#xff08;就是关系表而…

NetBeans可用性提示

的Java IDE都来了&#xff0c;因为在很长的路要走天的JBuilder的 &#xff08;尽管JBuilder中似乎是一个值得欢迎提前在时间&#xff09;。 当今的Java IDE&#xff08;例如NetBeans &#xff0c; Eclipse &#xff0c; IntelliJ IDEA和JDeveloper &#xff09;是非常先进的工具…

一个JVM进程启动后里面有几个线程

在写Java程序时&#xff0c;通常我们管只有一个main函数&#xff08;而没有别的Thread或Runnable的程序&#xff09;叫单线程程序。但是我们写的这个所谓的单线程程序只是JVM这个程序中的一个线程&#xff0c;JVM本身是一个多线程的程序&#xff0c;至少得有一个垃圾收集器线程…

WPF 反编译后错误处理

1. 首先&#xff0c;手动创建一个WPF工程&#xff08;WpfApplicationReflectorDemo&#xff09; 2. 把生成的WpfApplicationReflectorDemo.exe 拖到ILSpy里 3.点击 File -> Save Code...: 相应的代码会生成到指定地方。 4. 打开应用程序&#xff0c;并且编译它&#xff0c;此…

JavaFX 2 GameTutorial第1部分

介绍 我相信大多数软件开发人员可能会在年轻人&#xff08;年轻人&#xff09;一生中的某一时刻被迫创建游戏来帮助他们学习编程语言&#xff08;我知道我确实做到了&#xff09;。 以前&#xff0c;我的第一台计算机实际上是Franklin Ace 1000 &#xff0c;后来是Apple [] 。 …

虚拟现实-VR-UE4-认识UE4

VR的火热&#xff0c;让每个人都想参与一下&#xff0c; 公司在展会上面搞了一个VR的Demo&#xff0c;关注度超出预期&#xff0c;使得公司高层决定来个VR项目 所以 关于UE4 百度百科地址&#xff1a;http://baike.baidu.com/link?urlmEmbwOcqEuqtkfdu9lNdxVtWAkv0Q6UHZ4VgIHr…

java concurrent 例子_[Java Concurrent] 并发访问共享资源的简单案例

EvenGenerator 是一个偶数生成器&#xff0c;每调用一个 next() 就会加 2 并返回叠加后结果。在本案例中&#xff0c;充当被共享的资源。EvenChecker 实现了 Runnable 接口&#xff0c;可以启动新的线程执行 run() 任务&#xff0c;用于检测所指向的偶数生成器是否每次都返回偶…

OSGI实战第一章

第一章 解开OSGI的面纱 OSGI是什么&#xff1f;是Java平台的一个模块化层。模块化&#xff1a;软件应用程序的代码被分割为表示独立内容的逻辑单元&#xff0c;可简化开发&#xff0c;可通过强化逻辑模块的界限来提高可维护性。Java模块化的不足a) Java使用访问…

轻松完成Birt报告

这是使用Birt插件在Eclipse中构建报告的完整指南。 Birt或Business Intelligence and Reporting工具是一种无需编写太多Java代码即可生成报告的工具。 如果您使用的是ireport&#xff0c;那么您知道我在说什么&#xff1a;&#xff09;&#xff08;晶体报告..毫无意义&#xff…

MySQL 的 RowNum 实现

MySQL 下面没有RowNum&#xff0c;排序后序号却无法得到&#xff0c;比较麻烦&#xff01; SELECT rownum:rownum1 rownum, CollectSn From(SELECT rownum:0,bbgmain.* FROM qbdb.bbgmain WHERE collectsn! ORDER BY collectsn limit 10) t转载于:https://www.cnblogs.com/hym-…