典型32位机器中C语言,C语言中可变参数函数实现原理浅谈(7页)-原创力文档

本文深入探讨了C语言中可变参数函数的实现原理,基于函数调用的栈结构,阐述了参数从右到左入栈的规则,并详细分析了相关宏定义的作用,如va_start, va_arg和va_end等,这些宏如何帮助程序员在运行时访问和处理可变参数列表。此外,还解释了字对齐在参数存储中的重要性。
摘要由CSDN通过智能技术生成

C语言中可变参数函数实现原理浅析

1、C函数调用的栈结构

可变参数函数的实现与函数调用的栈结构密切相关,正常情况下C的函数参数入栈规则为__stdcall, 它是从右到左的,即函数中的最右边的参数最先入栈。例如,对于函数:

void fun(int a, int b, int c)

{

int d;

...

}

其栈结构为

0x1ffc-->d

0x2000-->a

0x2004-->b

0x2008-->c

对于任何编译器,每个栈单元的大小都是sizeof(int), 而函数的每个参数都至少要占一个栈单元大小,如函数 void fun1(char a, int b, double c, short d) 对一个32的系统其栈的结构就是

0x1ffc-->a (4字节)(为了字对齐)

0x2000-->b (4字节)

0x2004-->c (8字节)

0x200c-->d (4字节)

因此,函数的所有参数是存储在线性连续的栈空间中的,基于这种存储结构,这样就可以从可变参数函数中必须有的第一个普通参数来寻址后续的所有可变参数的类型及其值。

2. C语言通过几个宏来实现变参的寻址

根据函数调用的栈结构,标准C语言中,一般在stdarg.h头文件定义了下面的几个宏,用于实现变参的寻址及可变函数的设计,其中有可能不同的商业编译器的发行时实现的具体代码可能不一样,但是原理都是一样的。

//Linux 2.18内核

typedef char * va_list;

/*

Storage alignment properties -- 堆栈按机器字对齐

其中acpi_native_int是一个机器字,32位机的定义是:typedef u32 acpi_native_int

*/

#define _AUPBND (sizeof (acpi_native_int) - 1)

#define _ADNBND (sizeof (acpi_native_int) - 1)

/* Variable argument list macro definitions -- 变参函数内部实现需要用到的宏 */

#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))

#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))

#define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))

#define va_end(ap) (void) 0

在X86 32位机器中,以上这几个宏的用途主要是:

C语言传递参数是与__stdcall相同的,C语言传递参数时是用push指令从右到左将参数逐个压栈,因此C语言里通过栈指针来访问参数。虽然X86的push一次可以压2,4或8个字节入栈,C语言在压参数入栈时仍然是机器字的size为最小单位的,也就是说参数的地址都是字对齐的,这就是_bnd(X,bnd)存在的原因。汇编和C,编译出的X86函数一般在进入函数体后立即执行

push ebp

mov ebp, esp

这两条指令。首先把ebp入栈,然后将当前栈指针赋给ebp,以后访问栈里的参数都使用ebp作为基指针。

下面将对上面几个主要的宏进行分析:

#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))

计算类型为X的参数在栈中占据的字节数,是字对齐后的字节数。acpi_native_unit是一个机器字,32位机的定义是:typedef u32 acpi_native_uint;

显然,_AUPBND ,_ADNBND 的值是 4-1 == 3 == 0,按位取反( ~(bnd))就是0xfffffffc 。

因此,_bnd(X,bnd) 宏在32位机下是

( (sizeof(X) + 3)&0xfffffffc )

与&0xfffffffc相与后,最后两位是00,很明显,其作用是实现字对齐。

#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))

va_start(ap,A) ,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值