专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »C语言教程 » sprintf函数:sprintf函数详细介绍 »正文

sprintf函数:sprintf函数详细介绍

来源: 发布时间:星期四, 2009年2月12日 浏览:653次 评论:0


在将各种类型数据构造成串时sprf强大功能很少会让你失望由于sprf跟prf在使用方法上几乎只是打印地区别而已前者打印到串中后者则直接在命令行上输出这也导致sprf比prf有用得多

sprf是个变参定义如下:
sprf(char*buffer,constchar*format[,argument]...);
除了前两个参数类型固定外后面可以接任意多个参数而它精华显然就在第 2个参数:
格式化串上


prf和sprf都使用格式化串来指定串格式在格式串内部使用些以“%”开头格式介绍说明符(formatspecications)来占据个位置在后边变参列表中提供相应变量最终就会用相应位置变量来替代那个介绍说明符产生者想要


格式化数字
sprf最常见应用的莫过于把整数打印到串中所以spritnf在大多数场合可以替代
itoa

如:
//把整数123打印成串保存在s中
sprf(s,\"%d\",123);//产生\"123\"
可以指定宽度不足左边补空格:
sprf(s,\"%8d%8d\",123,4567);//产生:\"1234567\"
当然也可以左对齐:
sprf(s,\"%-8d%8d\",123,4567);//产生:\"1234567\"
也可以按照16进制打印:
sprf(s,\"%8x\",4567);//小写16进制宽度占8个位置右对齐
sprf(s,\"%-8X\",4568);//大写16进制宽度占8个位置左对齐

这样个整数16进制串就很容易得到但我们在打印16进制内容时通常想要种左边补0等宽格式那该如何做呢?很简单在表示宽度数字前面加个0就可以了
sprf(s,\"%08X\",4567);//产生:\"000011D7\"
上面以”%d”进行10进制打印同样也可以使用这种左边补0方式


这里要注意个符号扩展问题:比如假如我们想打印短整数()-1内存16进制表示形式在Win32平台上型占2个字节所以我们自然希望用4个16进制数字来打印它:
si=-1;
sprf(s,\"%04X\",si);
产生“FFFFFFFF”如何回事?spritnf是个变参除了前面两个参数的外后面参数都不是类型安全更没有办法仅仅通过个“%X”就能得知当初前参数压栈时被压进来到底是个4字节整数还是个2字节短整数所以采取了统4字节处理方式导致参数压栈时做了符号扩展扩展成了32位整数-1打印时4个位置不够了就把32位整数-18位16进制都打印出来了

如果你想看si本来面目那么就应该让编译器做0扩展而不是符号扩展(扩展时 2进制左边补0而不是补符号位):
sprf(s,\"%04X\",(unsigned)si);
就可以了或者:
unsignedsi=-1;
sprf(s,\"%04X\",si);


sprf和prf还可以按8进制打印整数使用”%o”注意8进制和16进制都不会打 [Page]
印出负数都是无符号实际上也就是变量内部编码直接16进制或8进制表示


控制浮点数打印格式
浮点数打印和格式控制是sprf大常用功能浮点数使用格式符”%f”控制默认保
留小数点后6位数字比如:
sprf(s,\"%f\",3.1415926);//产生\"3.141593\"
但有时我们希望自己控制打印宽度和小数位数这时就应该使用:”%m.nf”格式其中m表
示打印宽度n表示小数点后位数比如:
sprf(s,\"%10.3f\",3.1415626);//产生:\"3.142\"
sprf(s,\"%-10.3f\",3.1415626);//产生:\"3.142\"
sprf(s,\"%.3f\",3.1415626);//不指定总宽度产生:\"3.142\"


注意个问题你猜
i=100;
sprf(s,\"%.2f\",i);
会打出什么东东来?“100.00”?对吗?自己试试就知道了同时也试试下面这个:
sprf(s,\"%.2f\",(double)i);
个打出来肯定不是正确结果原因跟前面提到参数压栈时者并不知道跟i相对应格式控制符是个”%f”执行时本身则并不知道当年被压入栈里是个整数于是可怜保存整数i那4个字节就被不由分说地强行作为浮点数格式来解释了整个乱套了不过如果有人有兴趣使用手工编码个浮点数那么倒可以使用这种思路方法来检验下你手工编排结果是否正确


/Ascii码对照
我们知道在C/C语言中char也是种普通scalable类型除了字长的外它和
long这些类型没有本质区别只不过被大家习惯用来表示串而已(或许当年该把
这个类型叫做“然后现在就可以根据实际情况使用来把char通过typedef定义出来这样更合适些)于是使用”%d”或者”%x”打印便能得出它10进制或16进制ASCII码;反过来使用”%c”打印个整数便可以看到它所对应ASCII以下段把所有可见ASCII码对照表打印到屏幕上(这里采用prf注意”#”和”%X”合用时自动为16进制数增加”0X”前缀):
for(i=32;i<127;i){
prf(\"[%c]:%3d0x%#04X\\n\",i,i,i);


}


连接
sprf格式控制串中既然可以插入各种东西并最终把它们“连成串”自然也就能够连
从而在许多场合可以替代strcat但sprf能够次连接多个串(自然也可以同时
在它们中间插入别内容总的非常灵活)比如:
char*who=\"I\";
char*whom=\"CSDN\";
sprf(s,\"%slove%s.\",who,whom);//产生:\"IloveCSDN.\"
strcat只能连接串(段以’’结尾或叫做缓冲null-terminated-)但有时我们有两段缓冲区他们并不是以’’结尾比如许多从第 3方库中返回从硬件或者网络传输中读进来它们未必每序列后面都有个相应’’来结尾如果直接连接不管是sprf还是strcat肯定会导致非法内存操作而strncat也至少要求第个参数是个null-terminated-那该如何办呢?我们自然会想起前面介绍打印整数和浮点数时可以指定宽度串也比如: [Page]
chara1={’A’,’B’,’C’,’D’,’E’,’F’,’G’};
chara2={’H’,’I’,’J’,’K’,’L’,’M’,’N’};
如果:
sprf(s,\"%s%s\",a1,a2);//Don’tdothat!
十有 8 9要出问题了是否可以改成:
sprf(s,\"%7s%7s\",a1,a2);
也没好到哪儿去正确应该是:
sprf(s,\"%.7s%.7s\",a1,a2);//产生:\"ABCDEFGHIJKLMN\"
这可以类比打印浮点数”%m.nf”在”%m.ns”中m表示占用宽度(串长度不足时补空格超出了则按照实际宽度打印)n才表示从相应串中最多取用通常在打印串时m没什么大用还是点号后面n用自然也可以前后都只取部分:
sprf(s,\"%.6s%.5s\",a1,a2);//产生:\"ABCDEFHIJKL\"
在许多时候我们或许还希望这些格式控制符中用以指定长度信息数字是动态而不是静态指定许多时候要到运行时才会清楚到底需要取几个这种动态宽度/精度设置功能在sprf实现中也被考虑到了sprf采用”*”来占用个本来需要个指定宽度或精度常数数字位置同样而实际宽度或精度就可以和其它被打印变量样被提供出来于是上面例子可以变成:
sprf(s,\"%.*s%.*s\",7,a1,7,a2);
或者:
sprf(s,\"%.*s%.*s\",(a1),a1,(a2),a2);
实际上前面介绍打印、整数、浮点数等都可以动态指定那些常量值比如:
sprf(s,\"%-*d\",4,’A’);//产生\"65\"
sprf(s,\"%#0*X\",8,128);//产生\"0X000080\"\"#\"产生0X
sprf(s,\"%*.*f\",10,2,3.1415926);//产生\"3.14\"


打印地址信息
有时调试我们可能想查看某些变量或者成员地址由于地址或者指针也不过是个32位你完全可以使用打印无符号整数”%u”把他们打印出来:
sprf(s,\"%u\",&i);
不过通常人们还是喜欢使用16进制而不是10进制来显示个地址:
sprf(s,\"%08X\",&i);
然而这些都是间接思路方法对于地址打印sprf提供了专门”%p”:
sprf(s,\"%p\",&i);
我觉得它实际上就相当于:
sprf(s,\"%0*x\",2*(void*),&i);
利用sprf返回值
较少有人注意prf/sprf返回值但有时它却是有用spritnf返回了本次
最终打印到缓冲区中数目也就是说每当次sprinf结束以后你无须再
strlen便已经知道了结果长度如:
len=sprf(s,\"%d\",i); [Page]
对于正整数来说len便等于整数i10进制位数
下面是个完整例子产生10个[0,100)的间随机数并将他们打印到s中
以逗号分隔开
#
#
#
{
srand(time(0));
chars[64];
off=0;
for(i=0;i<10;i){
offsprf(s+off,\"%d,\",rand%100);
}
s[off-1]=’\\n’;//将最后个逗号换成换行符
prf(s);
0;
}
设想当你从数据库中取出条记录然后希望把他们各个字段按照某种规则连接成个字
符串时就可以使用这种思路方法从理论上讲他应该比不断strcat效率高strcat每次
都需要先找到最后那个’’位置而在上面给出例子中我们每次都利用sprf返回值把这
个位置直接记下来了


使用sprf常见问题
sprf是个变参使用时经常出问题而且只要出问题通常就是能导致崩溃内存访
但好在由sprf误用导致问题虽然严重却很容易找出无非就是那么几种情况
常用眼睛再把出错代码多看几眼就看出来了


1缓冲区溢出
个参数长度太短了给个大点地方吧当然也可能是后面参数
建议变参对应定要细心而打印串时尽量使用”%.ns”形式指定最大




2忘记了第个参数
低级得不能再低级问题用prf用得太惯了//偶就常犯:(


3变参对应出问题
通常是忘记了提供对应某个格式符变参导致以后参数统统错位检查检查吧
其是对应”*”那些参数都提供了吗?不要把个整数对应个”%s”编译器会觉得你
欺她太甚了(编译器是obj和exe妈妈应该是个女:P)


strftime
sprnitf还有个不错表妹:strftime专门用于格式化时间使用方法跟她表哥很像
大堆格式控制符只是毕竟小姑娘家心细她还要者指定缓冲区最大长度可能是为
了在出现问题时可以推卸责任吧这里举个例子:
time_tt=time(0);
//产生\"YYYY-MM-DDhh:mm:ss\"格式
chars[32];
strftime(s,(s),\"%Y-%m-%d%H:%M:%S\",localtime(&t));
sprf在MFC中也能找到他知音:CString::Formatstrftime在MFC中自然也有她同道:
CTime::Format对由于从面向对象哪里得到了赞助用以写出代码更觉优雅
2

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: