C语言中va(可变函数参数) 的另一种用法与危险事项

C语言中的可变参数va(va_arg) 大家应该比较熟悉了,主要是用来解决函数参数类型与个数不确定的问题,基本用法与详细请移步这里

通常的用法是把va_arg放在等号右边,提取其值来使用:

func( Type para1, Type para2, Type para3, ... )
{
    /****** Step 1 ******/
    va_list ap;
    va_start( ap, para3 ); //一定要“...”之前的那个参数
    
    /****** Step 2 ******/
    //此时ap指向第一个可变参数
    //调用va_arg取得里面的值
    Type xx = va_arg( ap, Type ); 
    
    //Type一定要相同,如:
    //char *p = va_arg( ap, char *);
    //int i = va_arg( ap, int );

    //如果有多个参数继续调用va_arg

    /****** Step 3 ******/
    va_end(ap); //For robust!
}

这里介绍va的另一种用法:把va_arg()当左值使用:

//函数定义:
PassInto(ID, ...) 
{

	va_list valist;

	va_start(valist, ID);

	*(uint32_t*)va_arg(valist, uint32_t*) = 10;
	va_end(valist);
}
//调用:
uint32_t value = 0;
PassInto(id, &value);

printf("%d", value);



得到结果是value被赋值为10。

可以看到,这里va_arg被放到了等号左边,好像很奇怪的用法,实际上分析一下,同放在右边原理都是一样的。因为不论va的原理如何(见上面的链接),

C语言的函数归根到底还是值传递的,在第一种通常的用法中,va值被取出来后赋值给其它变量,在第二种用法中,&value被当作va传了进去,

它的值其实就是一个指向value的指针,所以 va_arg(valist, uint32_t*) 取出的是一个uint32_t的指针,*(uint32_t*)va_arg(valist, uint32_t*) =10 即把这个指针强制类型转换为(uint32_t*)并加*号间接引用,

这样实际得到了变量value,现在把它赋值为10,就等价于

value = 10;

这样就完成了我们的全部操作,实现了对任意类型和个数的参数进行赋值。

这个方式超级灵活,但是注意不要进行下面的危险操作:

uint16_t value = 0;   //这里有变化
PassInto(id, &value);

后果可能很严重。为什么呢?因为参数类型不匹配,16位的参数被强迫当作32位来使用。我们的value同志此时只从系统那里申请到了16bit的空间,而

*(uint32_t*)va_arg(valist, uint32_t*) =10 

把10塞到了从value开始的32位空间,那么value之后的那16bit是哪里呢?由谁在用?不得而知。

如果运气好,没有人在用,程序无事,如果数据在用,那么数据会变化,系统在用,系统也跑偏。

反正我用的时候它没和我客气,系统直接崩溃了。



 





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值