当前位置:编程学习 > C/C++ >>

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

C语言中的可变参数va(va_arg) 大家应该比较熟悉了,主要是用来解决函数参数类型与个数不确定的问题,基本用法与详细请移步这里 http://www.zzzyk.com/kf/201202/119885.html
通常的用法是把va_arg放在等号右边,提取其值来使用:
[cpp]
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()当左值使用:
[cpp]
<pre class="cpp" name="code">//函数定义: 
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,就等价于
[cpp]
value = 10; 
这样就完成了我们的全部操作,实现了对任意类型和个数的参数进行赋值。
这个方式超级灵活,但是注意不要进行下面的危险操作:
[cpp]
uint16_t value = 0;   //这里有变化 
PassInto(id, &value); 
后果可能很严重。为什么呢?因为参数类型不匹配,16位的参数被易做图当作32位来使用。我们的value同志此时只从系统那里申请到了16bit的空间,而
[cpp]
*(uint32_t*)va_arg(valist, uint32_t*) =10  
把10塞到了从value开始的32位空间,那么value之后的那16bit是哪里呢?由谁在用?不得而知。
如果运气好,没有人在用,程序无事,如果数据在用,那么数据会变化,系统在用,系统也跑偏。
反正我用的时候它没和我客气,系统直接崩溃了。

摘自 herbert的知识库

补充:软件开发 , C语言 ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,