Linux C 函数可变参数处理

Kernel里面用得最多的printk()函数为例子:
asmlinkage int printk(const char *fmt, ...)
{
	va_list args;
	int r;

#ifdef CONFIG_KGDB_KDB
	if (unlikely(kdb_trap_printk)) {
		va_start(args, fmt);
		r = vkdb_printf(fmt, args);
		va_end(args);
		return r;
	}
#endif
	va_start(args, fmt);
	r = vprintk(fmt, args);
	va_end(args);

	return r;
}

在代码里面调用printk()进行打印:

printk("%s\n", "hello world");

函数参数由 右到左依次压栈,右边变量处于高地址。因此,在printk()函数内部,上面参数在栈中的位置为:


接下来,需要将 p 指向的 "hello world" 字符串地址获取出来。

include\acpi\platform\acenv.h

#ifndef va_arg

#ifndef _VALIST
#define _VALIST
typedef char *va_list;
#endif				/* _VALIST */

/*
 * Storage alignment properties
 */
#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_arg(ap, T)           (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
#define va_end(ap)              (void) 0
#define va_start(ap, A)         (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
看代码最直观,args 为 char * 变量, va_start() 获取传入函数的第一个变量的地址,即... 表示的变量,本例中,则是 p。对应 va_start 宏,先将保存fmt的地址取出(栈地址esp),然后对齐处理,取出p的值,根据该值既可以将所有的传入参数从栈中取出来。

最后调用 vprintk() 处理打印。

参考文档:http://www.eefocus.com/article/09-11/85907s.html













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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值