<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
五、使用文件字符串处理的功能。
1、目的
验证f_printf()函数的功能,学习变参数函数的编写和使用方法。
掌握格式化字符串的一些定义和用途。
2、有关格式控制串
格式控制串总是以%开始,后跟一些参数:
%【flags】【宽度】【精度控制】type。
前面三个是可选,而type是必须的参数。
(1) flag用于控制输出的 符号+(+-)、对齐方式-(左对齐)等。
(2) 宽度只控制输出的宽度,03,当字符数小于3个时,左边补0.
(3) 精度控制,主要针对浮点数。比如12.3456 如果%.2则只输出2位,变成12.34。
(4) 类型是必须的。这里主要分析这个。
3、源代码分析
int f_printf (
FIL* fil, /* Pointer to the file object */
const char* str, /* Pointer to the format string */
... /* Optional arguments... */
){ va_list arp;
UCHAR c, f, r;
ULONG val;
char s[16];
int i, w, res, cc;
va_start(arp, str); //arp实际是一个通用类指针,指向str后的第一个参数。
for (cc = res = 0; cc != EOF; res += cc) {
c = *str++;
if (c == 0) break; /* End of string */
if (c != '%') { /* Non escape cahracter */
cc = f_putc(c, fil); //如果不是%,表示正常字符,写入文件
if (cc != EOF) cc = 1; //cc是本次写对应的字符数字。当然如果写入不成功,返回EOF,则跳出循环
continue; //res是总共写入的数字。
}
w = f = 0; //从此处开始表示遇到了%后的处理
c = *str++; //取出下一个字符。
if (c == '0') { /* Flag: '0' padding */
f = 1; c = *str++; //如果是字符0,表示要控制宽度,flag第0位标志置位。取出下一字符
}
while (c >= '0' && c <= '9') { /* Precision */
w = w * 10 + (c - '0');
c = *str++; //依次取出后面的字符,如遇到034,则w=34。字符输出 }
if (c == 'l') { /* Prefix: Size is long int */
f |= 2; c = *str++; //如果遇到字符'l',表示长整形,标志第1位置位。 }
if (c == 's') { /* Type is string */
cc = f_puts(va_arg(arp, char*), fil); //如果遇到 ‘s’标志,将arp转换为char*指针,并指向下一个参数。
continue; //cc是字符串的长度,本次输入文件的字符数。
}
if (c == 'c') { /* Type is character */
cc = f_putc(va_arg(arp, int), fil); //字符以int类型出现,要占四个字节。
if (cc != EOF) cc = 1;
continue;
} r = 0; //如果字符'0'和'l'后,不是s和c,则下面继续处理
if (c == 'd') r = 10; /* Type is signed decimal */
if (c == 'u') r = 10; /* Type is unsigned decimal *///十进制
if (c == 'X') r = 16; /* Type is unsigned hexdecimal */
if (r == 0) break; /* Unknown type */
if (f & 2) { /* Get the value */
val = (ULONG)va_arg(arp, long);
} else {
val = (c == 'd') ? (ULONG)(long)va_arg(arp, int) : (ULONG)va_arg(arp, unsigned int);
} //如果设置了'l',标志,则将数据转换为长整形。从参数中取出来。
/* Put numeral string */ //下面是将数字转换为字符串。
if (c == 'd') {
if (val & 0x80000000) {
val = 0 - val;
f |= 4; //标志第二位表明这是个负数。
} }
i = sizeof(s) - 1; s = 0; //字符串最后一为以 '\0'结束。i指向尾端,往前扩展。
do { //同时处理十进制和十六进制。
c = (UCHAR)(val % r + '0'); //十进制时,1234/10,余数4+‘<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />0’,变成字符
if (c > '9') c += 7; //十六进制,3A表示大写A,但实际的字符A是0x41,中间差7.
s[--i] = c; //前一位存储该字符。
val /= r; //val变成123,也就是把尾端 一位去掉。
} while (i && val); //最多存储15位,要不然溢出。
if (i && (f & 4)) s[--i] = '-'; //如果为负数,还要加上符号标志。
w = sizeof(s) - 1 - w; //要求的宽度计算。8位宽,则填充从第7位开始。7-14,正好8位。
while (i && i > w) s[--i] = (f & 1) ? '0' : ' ';//如果0填充置位填充0,否则填充空格。i退到0,或者i推导W都结束填充。
cc = f_puts(&s, fil);
} va_end(arp);
return (cc == EOF) ? cc : res;
}
把代码看了一遍,基本还是能看懂。
4、移植。
(1)添加命令fstring,该命令一个参数,是用户字符串。以附加的写入到指定的文件fstring.txt。
(2)实习方法
以写文件的方式,打开文件,然后指针移动到文件末尾。调用代码f_printf(&File,”输入字符串%s/r/n”,(const char*)argv[1])来写入文件。
(3)代码实现
res=f_open( &FileStr, "0:/doc/fstring.txt",FA_WRITE ); //
res=f_lseek( &FileStr, FileStr.fsize );
f_printf (&FileStr,"用户输入:%s\r\n",(char*)argv[1] );
f_close (&FileStr );
功能比较简单,测试通过。
用户1547738 2010-4-1 08:44