使用可变参数的函数实现功能

一、编程任务和可变参数函数的介绍

1.编程任务:直观的且较为自由的在C语言编程中按位修改寄存器的值。
2.可变参数函数。
在定义某些函数时,函数参数的个数可能无法确定。例如int printf( const char* format, ...); 这时需要函数支持传递多个参数。 可变参数的函数至少需要一个确定的参数,其余用...来表示可变参数。
设计可变参数的函数需要“stdarg.h”头文件中的函数的功能。大致需要最基本的六步:
①引入必须的头文件 #include <stdarg.h>
②定义函数,如:int function(char n,...) {...}
③定义变量 va_list arg_prt; va_list型的变量,这里是arg_ptr,它是存储参数地址的指针。
④用va_start()初始化arg_prt指针,使其指向函数内确定参数后一项的参数。格式va_start(arg_prt,n);这里的“n”就是函数确定参数的表示符号。 对应文章一开始的printf的例子,这里的n就是format。
⑤用va_arg()取出各个可变参数。格式va_arg(arg_prt,type); 这里的type是指这个可变参数的类型,如“int”或者“char”这种。 如此,在va_arg()下,结合arg_prt的参数存储地址和type的参数类型,就可以得到这个参数。每次调用,指针arg_prt的值自动变化,不用手动修改地址。
⑥用va_end()清理指针。使用结束后调用va_end(arg_prt);清理使用的指针。

针对任务的原始代码如下。每次只能修改一个位。遇到修改多个位的情况就需要重复调用(函数递归能解决吗?目前尝试过,未解决)。
															unsigned int SETorCLR_BIT_32(unsigned int data32,unsigned char bit,unsigned char set_data)
															{
																if(set_data == 1)
																{
																	data32 |= (1 << bit);
																	return data32;
																}
																else if(set_data == 0)
																{
																	data32 &= ~(1 << bit);
																	return data32;
																}
																else
																{
																	printf("SETorCLR_BIT_32 set ERROR!\n");
																}
															}
														

二、使用可变函数重写以上函数

下面是新的修改函数。这个函数固定输入寄存器的当前值和“计划修改位数*2”的参数后,后面按照先确定改成0还是1后填入改在哪个位的顺序,就可以随意填入数据了。 这样一个函数,就直观且随意的修改寄存器上任意个位的数据,且在参数出错后返回寄存器的原值。
															#include <stdio.h>
															#include <stdarg.h>
															
															//m_value:原寄存器的值
															//n:一共修改多少位 * 2
															//...:修改成0或者1,输入对应的数值
															//...:修改到数据的第几位
															//按以上两次省略号的排序继续输入,直到修改完
															unsigned int SETorCLR_BIT_IN32BIT(unsigned int m_value,char n,...)
															{
																va_list arg_prt;
																char i,bit,value,item[n];
																unsigned int saved_m_value;
																
																saved_m_value = m_value; //保存原寄存器的数值
																va_start(arg_prt,n);
																for(i=0;i<n*2;i++)
																{
																	item[i] = va_arg(arg_prt,int); //导出所有可变参数
																}
																va_end(arg_prt); //使用完立即释放指针
																for(i=0;i<n;i+=2)
																{	
																	value = item[i];
																	bit = item[i+1];
																	if(value == 1)
																	{
																		m_value |= (1 << bit);
																	}
																	else if(value == 0)
																	{
																		m_value &= ~(1 << bit);
																	}
																	else
																	{
																	printf("SETorCLR_BIT_IN32BIT: Value %d set ERROR!\n",i);
																	return saved_m_value; //报错,且返回原寄存器的数值
																	}
																}
																return m_value;
															}
															
															//在主函数中调用验证一下
															int main()
															{
																unsigned int addr=0x00000000;
															    printf("*****************TEST******************* \n");
															    printf("%#X",SETorCLR_BIT_IN32BIT(addr,6,1,11,1,6,1,3));
																//SETorCLR_BIT_IN32BIT(addr,6,1,11,1,6,1,3)
																//调用含义:原寄存器值addr,修改3个位(3*2),第一个是改在第11位的1,第二个是改在第6位的1,第三个是改在第3位的1。
																//该函数可以同时允许多个0或者1在预定的位修改。如SETorCLR_BIT_IN32BIT(addr,6,1,11,0,6,1,3,0,21,1,25,0,4);
															    return 0;
															}
														
这样在使用mmap方式修改linux嵌入式平台的32位寄存器的时候,就即方便(仅需一个函数)又清晰(每一位的值,在哪一位)还安全(保存原寄存器值,出错返回原值)了。