code[class*="language-"], pre[class*="language-"] { color: rgba(51, 51, 51, 1); font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; text-align: left; white-space: pre; word-spacing: normal; word-break: normal; word-wrap: normal; line-height: 1.4; -moz-tab-size: 8; -o-tab-size: 8; tab-size: 8; -webkit-hyphens: none; -moz-hyphens: none; -ms-hyphens: none; hyphens: none }
pre[class*="language-"] { padding: 0.8em; overflow: auto; border-radius: 3px; background: rgba(245, 245, 245, 1) }
:not(pre)>code[class*="language-"] { padding: 0.1em; border-radius: 0.3em; white-space: normal; background: rgba(245, 245, 245, 1) }
.token.comment, .token.blockquote { color: rgba(150, 152, 150, 1) }
.token.cdata { color: rgba(24, 54, 145, 1) }
.token.doctype, .token.punctuation, .token.variable, .token.macro.property { color: rgba(51, 51, 51, 1) }
.token.operator, .token.important, .token.keyword, .token.rule, .token.builtin { color: rgba(167, 29, 93, 1) }
.token.string, .token.url, .token.regex, .token.attr-value { color: rgba(24, 54, 145, 1) }
.token.property, .token.number, .token.boolean, .token.entity, .token.atrule, .token.constant, .token.symbol, .token.command, .token.code { color: rgba(0, 134, 179, 1) }
.token.tag, .token.selector, .token.prolog { color: rgba(99, 163, 92, 1) }
.token.function, .token.namespace, .token.pseudo-element, .token.class, .token.class-name, .token.pseudo-class, .token.id, .token.url-reference .token.variable, .token.attr-name { color: rgba(121, 93, 163, 1) }
.token.entity { cursor: help }
.token.title, .token.title .token.punctuation { font-weight: bold; color: rgba(29, 62, 129, 1) }
.token.list { color: rgba(237, 106, 67, 1) }
.token.inserted { background-color: rgba(234, 255, 234, 1); color: rgba(85, 165, 50, 1) }
.token.deleted { background-color: rgba(255, 236, 236, 1); color: rgba(189, 44, 0, 1) }
.token.bold { font-weight: bold }
.token.italic { font-style: italic }
.language-json .token.property { color: rgba(24, 54, 145, 1) }
.language-markup .token.tag .token.punctuation { color: rgba(51, 51, 51, 1) }
code.language-css, .language-css .token.function { color: rgba(0, 134, 179, 1) }
.language-yaml .token.atrule { color: rgba(99, 163, 92, 1) }
code.language-yaml { color: rgba(24, 54, 145, 1) }
.language-ruby .token.function { color: rgba(51, 51, 51, 1) }
.language-markdown .token.url { color: rgba(121, 93, 163, 1) }
.language-makefile .token.symbol { color: rgba(121, 93, 163, 1) }
.language-makefile .token.variable { color: rgba(24, 54, 145, 1) }
.language-makefile .token.builtin { color: rgba(0, 134, 179, 1) }
.language-bash .token.keyword { color: rgba(0, 134, 179, 1) }
pre[data-line] { position: relative; padding: 1em 0 1em 3em }
pre[data-line] .line-highlight-wrapper { position: absolute; top: 0; left: 0; background-color: rgba(0, 0, 0, 0); display: block; width: 100% }
pre[data-line] .line-highlight { position: absolute; left: 0; right: 0; margin-top: 1em; background: linear-gradient(90deg, rgba(153, 122, 102, 0.1) 70%, rgba(153, 122, 102, 0)); pointer-events: none; line-height: inherit; white-space: pre }
pre[data-line] .line-highlight:before, pre[data-line] .line-highlight[data-end]:after { content: attr(data-start); position: absolute; top: 0.4em; left: 0.6em; min-width: 1em; padding: 0 0.5em; background-color: rgba(153, 122, 102, 0.4); color: rgba(245, 242, 240, 1); font: bold 65% / 1.5 sans-serif; text-align: center; vertical-align: 0.3em; border-radius: 999px; text-shadow: none; box-shadow: 0 1px rgba(255, 255, 255, 1) }
pre[data-line] .line-highlight[data-end]:after { content: attr(data-end); top: auto; bottom: 0.4em }
html body { font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; font-size: 16px; line-height: 1.6; color: rgba(51, 51, 51, 1); background-color: rgba(255, 255, 255, 1); overflow: initial; box-sizing: border-box; word-wrap: break-word }
html body>:first-child { margin-top: 0 }
html body h1, html body h2, html body h3, html body h4, html body h5, html body h6 { line-height: 1.2; margin-top: 1em; margin-bottom: 16px; color: rgba(0, 0, 0, 1) }
html body h1 { font-size: 2.25em; font-weight: 300; padding-bottom: 0.3em }
html body h2 { font-size: 1.75em; font-weight: 400; padding-bottom: 0.3em }
html body h3 { font-size: 1.5em; font-weight: 500 }
html body h4 { font-size: 1.25em; font-weight: 600 }
html body h5 { font-size: 1.1em; font-weight: 600 }
html body h6 { font-size: 1em; font-weight: 600 }
html body h1, html body h2, html body h3, html body h4, html body h5 { font-weight: 600 }
html body h5 { font-size: 1em }
html body h6 { color: rgba(92, 92, 92, 1) }
html body strong { color: rgba(0, 0, 0, 1) }
html body del { color: rgba(92, 92, 92, 1) }
html body a:not([href]) { color: inherit; text-decoration: none }
html body a { color: rgba(0, 136, 204, 1); text-decoration: none }
html body a:hover { color: rgba(0, 163, 245, 1); text-decoration: none }
html body img { max-width: 100% }
html body>p { margin-top: 0; margin-bottom: 16px; word-wrap: break-word }
html body>ul, html body>ol { margin-bottom: 16px }
html body ul, html body ol { padding-left: 2em }
html body ul.no-list, html body ol.no-list { padding: 0; list-style-type: none }
html body ul ul, html body ul ol, html body ol ol, html body ol ul { margin-top: 0; margin-bottom: 0 }
html body li { margin-bottom: 0 }
html body li.task-list-item { list-style: none }
html body li>p { margin-top: 0; margin-bottom: 0 }
html body .task-list-item-checkbox { margin: 0 0.2em 0.25em -1.8em; vertical-align: middle }
html body .task-list-item-checkbox:hover { cursor: pointer }
html body blockquote { margin: 16px 0; font-size: inherit; padding: 0 15px; color: rgba(92, 92, 92, 1); border-left: 4px solid rgba(214, 214, 214, 1) }
html body blockquote>:first-child { margin-top: 0 }
html body blockquote>:last-child { margin-bottom: 0 }
html body hr { height: 4px; margin: 32px 0; background-color: rgba(214, 214, 214, 1); border: 0 none }
html body table { margin: 10px 0 15px; border-collapse: collapse; border-spacing: 0; display: block; width: 100%; overflow: auto; word-break: keep-all }
html body table th { font-weight: bold; color: rgba(0, 0, 0, 1) }
html body table td, html body table th { border: 1px solid rgba(214, 214, 214, 1); padding: 6px 13px }
html body dl { padding: 0 }
html body dl dt { padding: 0; margin-top: 16px; font-size: 1em; font-style: italic; font-weight: bold }
html body dl dd { padding: 0 16px; margin-bottom: 16px }
html body code { font-family: Menlo, Monaco, Consolas, "Courier New", monospace; font-size: 0.85em !important; color: rgba(0, 0, 0, 1); background-color: rgba(240, 240, 240, 1); border-radius: 3px; padding: 0.2em 0 }
html body code::before, html body code::after { letter-spacing: -0.2em; content: " " }
html body pre>code { padding: 0; margin: 0; font-size: 0.85em !important; word-break: normal; white-space: pre; background: rgba(0, 0, 0, 0); border: 0 }
html body .highlight { margin-bottom: 16px }
html body .highlight pre, html body pre { padding: 1em; overflow: auto; font-size: 0.85em !important; line-height: 1.45; border: rgba(214, 214, 214, 1); border-radius: 3px }
html body .highlight pre { margin-bottom: 0; word-break: normal }
html body pre code, html body pre tt { display: inline; max-width: initial; padding: 0; margin: 0; overflow: initial; line-height: inherit; word-wrap: normal; background-color: rgba(0, 0, 0, 0); border: 0 }
html body pre code:before, html body pre tt:before, html body pre code:after, html body pre tt:after { content: normal }
html body p, html body blockquote, html body ul, html body ol, html body dl, html body pre { margin-top: 0; margin-bottom: 16px }
html body kbd { color: rgba(0, 0, 0, 1); border-top: 1px solid rgba(214, 214, 214, 1); border-right: 1px solid rgba(214, 214, 214, 1); border-bottom: 2px solid rgba(199, 199, 199, 1); border-left: 1px solid rgba(214, 214, 214, 1); padding: 2px 4px; background-color: rgba(240, 240, 240, 1); border-radius: 3px }
@media print { html body { background-color: rgba(255, 255, 255, 1) } html body h1, html body h2, html body h3, html body h4, html body h5, html body h6 { color: rgba(0, 0, 0, 1); page-break-after: avoid } html body blockquote { color: rgba(92, 92, 92, 1) } html body pre { page-break-inside: avoid } html body table { display: table } html body img { display: block; max-width: 100%; max-height: 100% } html body pre, html body code { word-wrap: break-word; white-space: pre } }
.markdown-preview { width: 100%; height: 100%; box-sizing: border-box }
.markdown-preview .pagebreak, .markdown-preview .newpage { page-break-before: always }
.markdown-preview pre.line-numbers { position: relative; padding-left: 3.8em; counter-reset: linenumber 0 }
.markdown-preview pre.line-numbers>code { position: relative }
.markdown-preview pre.line-numbers .line-numbers-rows { position: absolute; pointer-events: none; top: 1em; font-size: 100%; left: 0; width: 3em; letter-spacing: -1px; border-right: 1px solid rgba(153, 153, 153, 1); -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none }
.markdown-preview pre.line-numbers .line-numbers-rows>span { pointer-events: none; display: block; counter-increment: linenumber 1 }
.markdown-preview pre.line-numbers .line-numbers-rows>span:before { content: counter(linenumber); color: rgba(153, 153, 153, 1); display: block; padding-right: 0.8em; text-align: right }
.markdown-preview .mathjax-exps .MathJax_Display { text-align: center !important }
.markdown-preview:not([for="preview"]) .code-chunk .btn-group { display: none }
.markdown-preview:not([for="preview"]) .code-chunk .status { display: none }
.markdown-preview:not([for="preview"]) .code-chunk .output-div { margin-bottom: 16px }
{ width: 8px }
{ border-radius: 10px; background-color: rgba(0, 0, 0, 0) }
{ border-radius: 5px; background-color: rgba(150, 150, 150, 0.66); border: 4px solid rgba(150, 150, 150, 0.66); background-clip: content-box }
html body[for="html-export"]:not([data-presentation-mode]) { position: relative; width: 100%; height: 100%; top: 0; left: 0; margin: 0; padding: 0; overflow: auto }
html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview { position: relative; top: 0 }
@media screen and (min-width: 914px) { html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview { padding: 2em calc(50% - 457px + 2em) } }
@media screen and (max-width: 914px) { html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview { padding: 2em } }
@media screen and (max-width: 450px) { html body[for="html-export"]:not([data-presentation-mode]) .markdown-preview { font-size: 14px !important; padding: 1em } }
@media print { html body[for="html-export"]:not([data-presentation-mode]) #sidebar-toc-btn { display: none } }
html body[for="html-export"]:not([data-presentation-mode]) #sidebar-toc-btn { position: fixed; bottom: 8px; left: 8px; font-size: 28px; cursor: pointer; color: inherit; z-index: 99; width: 32px; text-align: center; opacity: 0.4 }
html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] #sidebar-toc-btn { opacity: 1 }
html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc { position: fixed; top: 0; left: 0; width: 300px; height: 100%; padding: 32px 0 48px; font-size: 14px; box-shadow: 0 0 4px rgba(150, 150, 150, 0.33); box-sizing: border-box; overflow: auto; background-color: inherit }
{ width: 8px }
{ border-radius: 10px; background-color: rgba(0, 0, 0, 0) }
{ border-radius: 5px; background-color: rgba(150, 150, 150, 0.66); border: 4px solid rgba(150, 150, 150, 0.66); background-clip: content-box }
html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc a { text-decoration: none }
html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc ul { padding: 0 1.6em; margin-top: 0.8em }
html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc li { margin-bottom: 0.8em }
html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .md-sidebar-toc ul { list-style-type: none }
html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview { left: 300px; width: calc(100% - 300px); padding: 2em calc(50% - 457px - 150px); margin: 0; box-sizing: border-box }
@media screen and (max-width: 1274px) { html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview { padding: 2em } }
@media screen and (max-width: 450px) { html body[for="html-export"]:not([data-presentation-mode])[html-show-sidebar-toc] .markdown-preview { width: 100% } }
html body[for="html-export"]:not([data-presentation-mode]):not([html-show-sidebar-toc]) .markdown-preview { left: 50%; transform: translateX(-50%) }
html body[for="html-export"]:not([data-presentation-mode]):not([html-show-sidebar-toc]) .md-sidebar-toc { display: none }

可变参函数指的是参数总个数不固定,只有调用时才知道到底有多少个参数

下面实现一个任意多个整数求和的可变参函数:

int Sum(int nItemCount, ...)
{
int i = 0, sum = 0;
va_list vp;
va_start(vp, nItemCount);
for (i = 0; i < nItemCount; i++)
{
sum += va_arg(vp, int);
}
va_end(vp);
return sum;
} int main()
{
Sum(6, 1, 2, 3, 4, 5, 6);
return 0;
}

先铺垫一下:

该函数调用约定没有指明,VC++编译器默认为_cdecl,那么其传参方向从右到左,nItemCount最后入栈,

栈帧如下:

VC++中va_list,va_start,va_arg,va_end定义如下:

typedef char *  va_list;
#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 ) #ifdef __cplusplus
#define _ADDRESSOF(v) ( &reinterpret_cast<const char &>(v) )
#else /* __cplusplus */
#define _ADDRESSOF(v) ( &(v) )
#endif /* __cplusplus */

va_list其实就是char*的别名,我这里编译的是Windows 32位程序,所以VC++将参数变量和局部变量的起始

地址都安排在能够模4(对4取余结果为0)地地址,那么在可变参函数内要正确的取出参数,则需要计算每一个

参数的起始地址,_crt_va_start和_crt_va_arg宏就实现了取出参数的功能,先来看看_crt_va_start:

_crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

_crt_va_start宏的功能就是取出可变参数列表("..."表示的那一部分参数)中的第一个参数(对于上面例子来说,也就是函数Sum(int nItemCount, ...)中紧挨着nItmecount的下一个参数)因为可变参函数的第一个参数是明确的(对于上面例子来说也就是Sum函数的nItemCount参数),所以可变参数列表中的第一个参数的内存地址为:

nItemCount的内存地址+nItemCount模4对齐后的大小

而_INTSIZEOF宏就是计算一个参数类型模4对齐后的大小,分析一下它:

#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

它用到了这样一个数学技巧:一个整数M要想成为整数N的最小整数倍,则需要用S=((M+N-1)/N)*N计算,S就是大于等于M

的整数中能够模N的最小的那个整数

例如: 3对4取余不为0,S=((3+4-1)/4)*4=4,这里4就是大于3的整数中能够模4的最小整数

5对4取余不为0,S=((5+4-1)/4)*4=8,这里8就是大于5的整数中能够模4的最小整数

对于这个公式:S=((M+N-1)/N)*N,当N为2的n次方的时候,可以用移位代替除法:((M+N-1)>>n)<<n,而_INTSIZEOF

中,是对sizeof(int)进行对齐,所以公式就变为((M+N-1)>>2)<<2,也就是将(M+N-1)的先右移两个二进制位,在左移

两个二进制位,其实相当于清零了(M+N-1)的低两位,sizeof(int) - 1结果为3,转换成二进制就是0x00000011,在用

"~"取反的到结果0x11111100,在和 ( (sizeof(n) + sizeof(int) - 1) 进行位与运算即可将其低两位清零,从而

达到目的。

再来看看_crt_va_arg(ap,t)这个宏,这个宏的作用就是取出当前参数并将指针指向下一个参数,这个宏原理_crt_va_start一样,都需要上一个参数的起始内存地址和上一个参数的类型,才能推导出下一个参数的内存地址,

分析一下:

ap += _INTSIZEOF(t)使得ap指向下一个参数,(ap += _INTSIZEOF(t)) - _INTSIZEOF(t)将得到一个指向上

一个参数的指针(这是个右值),((t)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))将这个指针(右值)强转为t类

型的指针,然后在取值

最后_crt_va_end(ap)宏进行收尾工作,将指针ap置为NULL

一般可变参函数第一个参数都是记录可变参数的个数,例如printf和scanf的第一个参数就是格式化字符串,其内部通过

解析格式化字符串中的"%c,%d"等格式说明符来判断参数的个数以及类型,从而正确的取出对应参数。

C语言可变参函数分析的更多相关文章

  1. 利用R语言打造量化分析平台

    利用R语言打造量化分析平台 具体利用quantmod包实现对股票的量化分析 1.#1.API读取在线行情2.#加载quantmod包3.if(!require(quantmod)){4. instal ...

  2. R语言重要数据集分析研究——需要整理分析阐明理念

    1.R语言重要数据集分析研究需要整理分析阐明理念? 上一节讲了R语言作图,本节来讲讲当你拿到一个数据集的时候如何下手分析,数据分析的第一步,探索性数据分析. 统计量,即统计学里面关注的数据集的几个指标 ...

  3. Go语言的前景分析

    本文为原创文章,转载注明出处,asdfasdfasdf 欢迎扫码关注公众号flysnow_org或者网站http://www.flysnow.org/,第一时间看后续精彩文章.觉得好的话,顺手分享到朋 ...

  4. Go将统治下一个10年?Go语言发展现状分析

    “本文是国内Go语言大中华区首席布道师——许式伟,在QCon2015上海站上的分享.他预测Go语言10年内一定会超过C和java,并且统治这一个10年. Go语言语法及标准库变化 Go从1.0版本到现 ...

  5. 猴子吃桃问题之《C语言经典案例分析》

    猴子吃桃问题之<C语言经典案例分析>一.[什么是猴子吃桃]       猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个.第二天早上又将第一天剩下的桃子吃掉一半 ...

  6. Go语言源码分析之unsafe

    Go语言源码分析之unsafe 1.什么是unsafe unsafe 库让 golang 可以像C语言一样操作计算机内存,但这并不是golang推荐使用的,能不用尽量不用,就像它的名字所表达的一样,它 ...

  7. C语言中变参函数传参探究

    背景引入 近期在看一本书,叫做<嵌入式C语言自我修养>,写的内容对我帮助很大,是一本好书.在第6章,GNU C编译器扩展语法精讲一节,这本书给出了一些变参函数的例子: //1.变参函数初体 ...

  8. Go语言的堆栈分析

    本文为理解翻译,原文地址:http://www.goinggo.net/2015/01/stack-traces-in-go.html Introduction 在Go语言中有一些调试技巧能帮助我们快 ...

  9. 03-第一个C语言程序的分析

    本文目录 一.代码分析 二.开发和运行C程序的步骤 三.总结 说明:这个C语言专题,是学习iOS开发的前奏.也为了让有面向对象语言开发经验的程序员,能够快速上手C语言.如果你还没有编程经验,或者对C语 ...

随机推荐

  1. 使用 js 实现十大排序算法: 基数排序

    使用 js 实现十大排序算法: 基数排序 基数排序 refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!

  2. 新三板 & 挂牌费用

    新三板 & 挂牌费用 关于拟申请公司股票在全国中小企业股份转让系统终止挂牌的提示性公告 https://pilu.tianyancha.com/announcement/ef51e981910 ...

  3. Electron in Action

    Electron in Action $ yarn add -D electron@latest # OR $ npm i -D electron@latest https://www.electro ...

  4. JavaScript Best Practice

    JavaScript Best Practice Clean, maintainable, execute code

  5. Flutter Navigator2.0

    Example 1 import 'package:dart_printf/dart_printf.dart'; import 'package:flutter/material.dart'; cla ...

  6. git stash & git stash pop

    git stash & git stash pop $ git checkout feature/select-seat-system $ git checkout feature/app-d ...

  7. arrayBuffer 转base64

    var buffer = new ArrayBuffer(8);// buffer 是接收到后台的流 function _arrayBufferToBase64( buffer ) { var bin ...

  8. Flutter: Dismissible 通过在指示的方向上拖动来解除的Widget

    API class _MyHomeState extends State<MyHome> { @override Widget build(BuildContext context) { ...

  9. Techme INC:红光和近红外光疗法有效加速肌肉恢复,美国橄榄球队已采用

    Techme INC创始人兼董事长MADELEINE VAUGHAN表示:在运动结束后,肌肉纤维因为细微损伤造成酸痛情形,即是延迟性肌肉酸痛-DOMS.这类酸痛发生时,需要适度的恢复,避免造成肌肉拉伤 ...

  10. python进阶(11)生成器

    生成器 利用迭代器,我们可以在每次迭代获取数据(通过next()方法)时按照特定的规律进行生成.但是我们在实现一个迭代器时,关于当前迭代到的状态需要我们自己记录,进而才能根据当前状态生成下一个数据. ...