使用可变参数的函数实现功能
一、编程任务和可变参数函数的介绍
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位寄存器的时候,就即方便(仅需一个函数)又清晰(每一位的值,在哪一位)还安全(保存原寄存器值,出错返回原值)了。