C语言中的宏 #define _INTSIZEOF(n) 与 可变参数函数

在学习可变参数时遇到宏

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

目的是将求出n对齐后的字节数,从这里来看应该是按照4字节的整数倍来对齐,为什么这个宏可以实现4字节的整数倍呢?

首先 (sizeof(n)+sizeof(int)-1) 在 sizeof(int) 时相当于( sizeof(n)+3 ) 如果 用 ( sizeof(n)+3 )/4*4, 则结果为4字节的整数倍。

所以 ( sizeof(n)+3 )&~(sizeof(int) - 1)  应该相当于 ( sizeof(n)+3 )/4*4, 这是为什么呢?

~(sizeof(int) - 1)  就是 ~(4 - 1)  = = ~(3)  , 二进制 11111100

令x=n/4, y=n%4,  则 n=n/4*4+y, n/4*4是对齐后的字节数,而 m & 11111100刚好将后两位,即余数部分置为了0,保留的刚好是n/4*4部分。

所以

n & ~(sizeof(int) - 1) ) 的作用是去掉n对sizeof(int)的余数部分

((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) 的在作用是对n的字节数按照 sizeof(int) 的整数倍进行对齐(不足需要补充)。

这个宏的设计很巧妙,实际少是用位运算替代了除法操作,从而提高计算效率。


那么为什么要对齐呢?

因为在函数调用时,参数是通过堆栈进行调用的,估计系统为了便于管理堆栈和参数,将压入堆栈的参数的大小进行了固化,其实字节对齐在其他地方也经常使用,如结构体和类的大小等。sizeof() 获得的仅仅是逻辑长度,并不是真实的物理长度?


另外三个和可变参数相关的宏。

#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )

v是第一个固定参数, ap 用于指向其他的可变参数, 这里 ap = (va_list)&v + _INTSIZEOF(v) 使得ap指向第一个固定参数后面的第一个可变参数(压入堆栈时,先压入固定参数,再依次压入可变参数,具体方式和硬件和系统有关),如printf(char *pformat, ....)

#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

实现将ap指向的参数取出赋给t,并且让p指向下一个可变参数 具体是先(ap += _INTSIZEOF(t)) 之后用 (*( t *)(ap-_INTSIZEOF(t))),设计的也很巧

#define va_end(ap) ( ap = (va_list)0 )

最后将ap指针设置为空。

typedef char *  va_list;  va_list 就是char *类型的指针。


这些宏在stdarg.h头文件中。









發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章