商务网站建设的一般流程是什么电子商务网站建设与维护李建忠下载
目录
- 1.宏含义及使用
 - 2.宏原理分析
 - 1.原理
 - 2.宏理解
 
1.宏含义及使用
- 依赖库
stdarg.h va_list- 其实就是
char*类型,方便后续按照字节进行指针移动 
- 其实就是
 va_start(arg, num)- 使
arg指向可变参数部分(num后面) 
- 使
 va_arg(arg, int)- 先让
arg指向下个元素,然后使用相对位置 – 偏移量,访问当前元素- 即:访问了当前数据的同时,又让arg指向了后续元素
 
 
- 先让
 va_end- 将arg指针设置为
NULL,防止野指针 
- 将arg指针设置为
 - 使用示例
int FindMax(int num, ...) {va_list arg;va_start(arg, num);int max = va_arg(arg, int); // 根据类型,获取可变参数列表中的第一个数据//获取并比较其他的for (int i = 0; i < num - 1; i++){int cur = va_arg(arg, int);if (max < curr){max = curr;}}va_end(arg);return max; }int main() {int max = FindMax(5,11,22,33,44,55);printf("max = %d\n", max);return 0; } - 注意事项 
- 可变参数必须从头到尾逐个访问 
- 如果在访问了几个可变参数之后想半途终止,这是可以的
 - 但是,如果想一开始就访问参数列表中间的参数,那是不行的
 
 - 参数列表中至少有一个命名参数 
- 如果连一个命名参数都没有,就无法使用
va_start 
 - 如果连一个命名参数都没有,就无法使用
 - 这些宏是无法直接判断实际存在参数的数量
 - 这些宏无法判断每个参数的类型
 - 如果在
va_arg中指定了错误的类型,那么其后果是不可预测的- 整型提升除外
 
 
 - 可变参数必须从头到尾逐个访问 
 
2.宏原理分析
1.原理
- 可变参数列表对应的函数,最终调用也是函数调用,也要形成栈帧
 - 栈帧形成前,临时变量是要先入栈的,根据之前所学,参数之间位置关系是固定的
 - 通过之前的汇编的学习,发现了短整型在可变参数部分,会默认进行整形提升(char short float整型提升成int/double),那么函数内部在提取该数据的时候,就要考虑提升之后的值,如果不加考虑,获取数据可能会报错或者结果不正确
 
2.宏理解
- 都有什么?
// va_list其实就是char*类型,方便后续按照字节进行指针移动 typedef char * va_list;#define va_start _crt_va_start #define va_arg _crt_va_arg #define va_end _crt_va_end #define va_start _crt_va_start依赖实现// 这个宏特别好理解,结合栈帧中临时参数的压入位置 #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )#define va_arg _crt_va_arg依赖实现// 这个设计特别巧妙,先让ap指向下个元素,然后使用相对位置-偏移量,访问当前元素 // 访问了当前数据的同时,还让ap指向了后续元素,一举两得 #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )#define va_end _crt_va_end依赖实现// 这个宏特别好理解,将ap指针设置为NULL #define _crt_va_end(ap) ( ap = (va_list)0 )_ADDRESSOF(v)理解// 取参数的地址,也很好理解 #define _ADDRESSOF(v) ( &(v) )_INTSIZEOF(n)理解,难点#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )- 前提: 
- 为了后面方便表述,假设
sizeof(n)的值 -->n(char 1,short 2, int 4) - 在32位平台下测试,
sizeof(int) == 4,其他情况暂时不考虑 
 - 为了后面方便表述,假设
 _INTSIZEOF(n)的意思:计算一个最小数字x,满足x>=n && x%4==0,其实就是一种4字节对齐的方式- 是什么? 
- 比如
n是:1,2,3,4 对n进行向sizeof(int)的最小整数倍取整的问题 就是 4 - 比如
n是:5,6,7,8 对n进行向sizeof(int)的最小整数倍取整的问题 就是 8 
 - 比如
 - 为什么要有这个4字节对齐 
- 结合之前栈帧的学习和上面代码的测试结果
 
 - 怎么办到的 
- 第一步理解:4的倍数 
- 既然是4的最小整数倍取整,那么本质是:
x=4*m,m是具体几倍,对7来讲,m就是2,对齐的结果就是8,而m具体是多少,取决于n是多少- 如果
n能整除4,那么m就是n/4 - 如果
n不能整除4,那么m就是n/4+1 
 - 如果
 - 上面是两种情况,如何合并成为一种写法呢? 
- 常见做法是 
(n+sizeof(int)-1))/sizeof(int) -> (n+4-1)/4 - 如果
n能整除4- 那么
m就是(n+4-1)/4 -> (n+3)/4,+3的值无意义,会因取整自动消除,等价于n/4 
 - 那么
 - 如果
n不能整除4- 那么n=最大能整除4部分+r,
1 <= r < 4 - 那么m就是(n+4-1)/4 --> (能整除4部分+r+3)/4,其中
4 <= r+3 < 7--> 能整除4部分/4 + (r+3)/4 -> n/4+1 
 - 那么n=最大能整除4部分+r,
 
 - 常见做法是 
 
 - 既然是4的最小整数倍取整,那么本质是:
 - 第二步理解:最小4字节对齐数 
- 搞清楚了满足条件最小是几倍问题,那么,计算一个最小数字
x,满足x>=n && x%4==0,就变成了((n+sizeof(int)-1)/sizeof(int))[最小几倍] * sizeof(int)[单位大小] -> ((n+4-1)/4)*4 - 这样就能求出来4字节对齐的数据了,其实上面的写法,在功能上,已经和源代码中的宏等价了
 
 - 搞清楚了满足条件最小是几倍问题,那么,计算一个最小数字
 - 第三步理解:理解源代码中的宏 
- 拿出简洁写法:
((n+4-1)/4)* 4,设w=n+4-1,那么表达式可以变化成为(w/4)*4,而4就是 2 2 2^2 22,w/4不就相当于右移两位吗?再次*4不就相当左移两位吗?先右移两位,在左移两位,最终结果就是,最后2个比特位被清空为0! - 需要这么费劲吗? 
w & ~3不香吗?
 - 所以,简洁版:
(n+4-1) & ~(4-1) - 原码版:
( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ),无需先/,再* 
 - 拿出简洁写法:
 
 - 第一步理解:4的倍数 
 
- 是什么? 
 
- 前提: 
 - 图解

 
