可变参数列表《二》(可变参数列表的宏的讲解与实现)

  个人主页:欢迎大家光临——>沙漠下的胡杨

  各位大帅哥,大漂亮

 如果觉得文章对自己有帮助

 可以一键三连支持博主

 你的每一分关心都是我坚持的动力

 

 ☄: 本期重点:可变参数列表的宏的讲解与实现

  希望大家每天都心情愉悦的学习工作。 


可变参数的原理:

设计巧妙的va_arg

_INESIZEOF讲解

下面我们进行下数学的论证:



可变参数的原理:

1.可变参数列表对应的是函数,最后也要形成函数调用,形成栈帧。

2.栈帧形成前,对应的是临时变量要先入栈,入栈时,参数的相对位置是固定的。

3.通过汇编的学习(movsx使发生整形提升),发现了短整型在可变参数部分,会默认升为int型,那么在函数提取数据时就要考虑整形提升之后的值啦,如果不加考虑,获取数据可能会出错。

可变参数的宏的讲解


#include //va_arg等的头文件


char GetMax(int num, ...)
{
	va_list arg;
	va_start(arg, num);
	int max = va_arg(arg, int);
	for (int i = 1; i < num; i++)
	{
		int cur = va_arg(arg, int);
		if (cur>max)
		{
			max = cur;

		}
	}
	va_end(arg);

	return max;
}


int main()
{
	char a = 'a';
	char b = 'b';
	char c = 'c';
	char d = 'd';
	char e = 'e';

	char max = GetMax(5, a, b, c, d, e);

	printf("max = %c\n", max);

	return 0;
}

代码如上:

首先,我们重点研究的宏是:

可变参数列表《二》(可变参数列表的宏的讲解与实现)_第1张图片

 

可变参数列表《二》(可变参数列表的宏的讲解与实现)_第2张图片

重点研究的宏只有这几个,还是以上面的代码例子为主进行研究。

 va_start:

 va_start 就是 _crt_va_start 这个宏对应到上述代码中就是把传进来的 num 这个地址进行强制类型转化为 char*(va_list),然后在加上_INTSIZEOF(num)的大小。(_INTSIZEOF其实就是四字节向上取整),所以 ap = (char *) &num + 4。

看下图分析下:

可变参数列表《二》(可变参数列表的宏的讲解与实现)_第3张图片

 2. va_end

va_end其实就是把 0 地址转化为 char * 然后进行赋值啦,就是防止 ap 为野指针。

可变参数列表《二》(可变参数列表的宏的讲解与实现)_第4张图片

设计巧妙的va_arg

这个宏设计的非常巧妙,我们要画图来进行分析:

可变参数列表《二》(可变参数列表的宏的讲解与实现)_第5张图片

这个 va_arg 设计的理念是,先把指向的内容下移并赋值,这就是把指向改变了,在让 ap 减去4这相当于是访问这个 ap到 ap-4的内容,这个设计就非常巧妙

那么前面的 *(t*) 什么意思呢?

首先我们的ap指针是 char *类型的,所以我们访问元素时不是 char * 类型的,所以我们应该把ap强制转化为(t*)的。以便我们进行提取符合类型大小的数据

_INESIZEOF讲解

这个宏设计的也很巧妙,这个宏的本质是,把传进来的的数据进行4字节向上取整,简单就是,不够4的部分都按照4字节处理,比如char 和 short 。

_INSIZEOF(char)   ( (sizeof(char) +sizeof(int) - 1) & ~(szieof(4) - 1) ) 这个其实上就是 4 & ~3计算后为 4。所以char类型进行读取时我们应该为 int 类型4字节读取。

_INSIZEOF(short)   ( (sizeof(short) +sizeof(int) - 1) & ~(szieof(4) - 1) ) 这个就是 5 &~3,结果还是4, 所以我们进读取时,不够4的部分都按照4字节处理吗,因为取整时我们就是向4+字节对齐了。

下面我们进行下数学的论证:

1.首先取整不就是看是 4 的几倍,这个倍数取整就可以啦,如果是5,这个倍数是1.25,向上取整就是2,如果是3,这个倍数是 0.75,向上取整为1,如果是4,刚好倍数是1,不用取整,所以我们如果想把这些办法归结到一种写法。

最常见的是数学表达(n-1+4)/  4。(此时不考虑取整)

写成C语言:( n + sizeof(int) - 1)/ sizeof( int )

2.上述的情况了解啦,就考虑最小对齐数的问题。

那么最小对齐数其实上就是 x >= n && x%4 == 0,首先是倍数是最小的,并且还要能够整除4的数字,写成C语言:

( ( n + sizeof ( int ) - 1 ) / sizeof ( int ) )  *  sizeof ( int )   ---> ( ( n + 4 - 1 ) / 4 ) * 4

3.源码中的宏的理解

首先我们知道,在2进制下,我们从右向左权重为,1,2,4,....所以可以看出来,我们要判断是不是4的倍数,首先要看最低的两位是否为0,我们要求4的最小取整倍数,首先是要把最低的两位比特位置为0,上述的数学方法中我们是先除4,再乘4,把最低两位置为0,源码中我们直接使用的是 w & ~3把最后两位比特位清零啦。

简洁版的:(n+4-1) & ~(4-1) --> (n+3) & ~3

源码: ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

你可能感兴趣的:(函数栈帧的创建,c语言)