在将各种cd的数据构造成字符串时Qsprintf 的强大功能很会让你失望。由于sprintf 跟printf 在用法上几乎一P只是打印的目的地不同而已Q前者打印到字符串中Q后者则直接在命令行上输出。这也导致sprintf 比printf 有用得多?br /> sprintf 是个变参函数Q定义如下:
int sprintf( char *buffer, const char *format [, argument] ... );
除了前两个参数类型固定外Q后面可以接L多个参数。而它的精华,昄在W二个参敎ͼ
(1)格式化字W串上?/span>
printf 和sprintf 都用格式化字符串来指定串的格式Q在格式串内部用一些以“%”开头的格式说明W(format specificationsQ来占据一个位|,在后边的变参列表中提供相应的变量Q最l函数就会用相应位置的变量来替代那个说明W,产生一个调用者想?的字W串?br /> 格式化数字字W串
sprintf 最常见的应用之一莫过于把整数打印到字W串中,所以,spritnf 在大多数场合可以替代itoa?br /> 如:
//把整?23 打印成一个字W串保存在s 中?br /> sprintf(s, "%d", 123); //产生"123"
可以指定宽度Q不的左边补空|
sprintf(s, "%8d%8d", 123, 4567); //产生Q? 123 4567"
当然也可以左寚wQ?br /> sprintf(s, "%-8d%8d", 123, 4567); //产生Q?123 4567"
也可以按?6 q制打印Q?br /> sprintf(s, "%8x", 4567); //写16 q制Q宽度占8 个位|,叛_?br /> sprintf(s, "%-8X", 4568); //大写16 q制Q宽度占8 个位|,左对?br /> q样Q一个整数的16 q制字符串就很容易得刎ͼ但我们在打印16 q制内容Ӟ通常惌一U左边补0 的等宽格式,那该怎么做呢Q很单,在表C宽度的数字前面加个0 可以了?br /> sprintf(s, "%08X", 4567); //产生Q?000011D7"
上面?#8221;%d”q行?0 q制打印同样也可以用这U左边补0 的方式?br /> q里要注意一个符h展的问题Q比如,假如我们x印短整数QshortQ?1 的内?6 q制表示形式Q在Win32 q_上,一个short 型占2 个字节,所以我们自然希望用4 ?6 q制数字来打印它Q?br /> short si = -1;
sprintf(s, "%04X", si);
产生“FFFFFFFF”Q怎么回事Q因为spritnf 是个变参函数Q除了前面两个参C外,后面的参数都不是cd安全的,函数更没有办法仅仅通过一?#8220;%X”p得知当初函数调用前参数压栈时被压q来的到?是个4 字节的整数还是个2 字节的短整数Q所以采取了l一4 字节的处理方式,D参数压栈时做了符h展,扩展成了32 位的整数-1Q打印时4 个位|不够了Q就?2 位整?1 ? ?6 q制都打印出来了?br /> 如果你想看si 的本来面目,那么应该让~译器做0 扩展而不是符h展(扩展时二q制左边? 而不是补W号位)Q?br /> sprintf(s, "%04X", (unsigned short)si);
可以了。或者:
unsigned short si = -1;
sprintf(s, "%04X", si);
sprintf 和printf q可以按8 q制打印整数字符Ԍ使用”%o”。注? q制?6 q制都不会打
印出负数Q都是无W号的,实际上也是变量的内部编码的直接?6 q制? q制表示?br /> 控制点数打印格?br /> 点数的打印和格式控制是sprintf 的又一大常用功能,点C用格式符”%f”控制Q默认保
留小数点? 位数字,比如Q?br /> sprintf(s, "%f", 3.1415926); //产生"3.141593"
但有时我们希望自己控制打印的宽度和小C敎ͼq时应该用:”%m.nf”格式Q其中m ?br /> C打印的宽度Qn 表示数点后的位数。比如:
sprintf(s, "%10.3f", 3.1415626); //产生Q? 3.142"
sprintf(s, "%-10.3f", 3.1415626); //产生Q?3.142 "
sprintf(s, "%.3f", 3.1415626); //不指定d度,产生Q?3.142"
注意一个问题,你猜
int i = 100;
sprintf(s, "%.2f", i);
会打Z么东东来Q?#8220;100.00”Q对吗?自己试试q道了Q同时也试试下面q个Q?br /> sprintf(s, "%.2f", (double)i);
W一个打出来的肯定不是正结果,原因跟前面提到的一P参数压栈时调用者ƈ不知道跟i相对应的格式控制W是?#8221;%f”。而函数执行时函数本n则ƈ?知道当年被压入栈里的是个整数Q于是可怜的保存整数i 的那4 个字节就被不由分说地作ؓ点数格式来解释了,整个乱套了。不q,如果有h有兴用手工编码一个QҎQ那么倒可以用这U方法来验一下你手工~?排的l果是否正确?br />
(2)字符/Ascii 码对?/span>
我们知道Q在C/C++语言中,char 也是一U普通的scalable cdQ除了字长之外,它与shortQ?br /> intQlong q些cd没有本质区别Q只不过被大家习惯用来表C字W和字符串而已。(或许当年该把
q个cd叫做“byte”Q然后现在就可以Ҏ实际情况Q用byte 或short 来把char 通过typedef 定义出来Q这h合适些Q于是,使用”%d”或?#8221;%x”打印一个字W,便能得出它的10 q制?6 q制的ASCII 码;反过来,使用”%c”打印一个整敎ͼ便可以看到它所对应的ASCII 字符。以下程序段把所有可见字W的ASCII 码对照表打印到屏q上Q这里采用printfQ注?#8221;#”?#8221;%X”合用时自动ؓ16 q制数增?#8221;0X”前缀Q:
for(int i = 32; i < 127; i++) {
printf("[ %c ]: %3d 0x%#04X/n", i, i, i);
}
(3)q接字符?/span>
sprintf 的格式控制串中既然可以插入各U东西,q最l把它们“q成一?#8221;Q自然也p够连
接字W串Q从而在许多场合可以替代strcatQ但sprintf 能够一ơ连接多个字W串Q自然也可以同时
在它们中间插入别的内容,M非常灉|Q。比如:
char* who = "I";
char* whom = "CSDN";
sprintf(s, "%s love %s.", who, whom); //产生Q?I love CSDN. "
strcat 只能q接字符Ԍ一D以’’l尾的字W数l或叫做字符~冲Qnull-terminated-stringQ,但有时我们有两段字符~冲区,他们q不是以 ’’l尾。比如许多从W三方库函数中返回的字符数组Q从g或者网l传输中读进来的字符,它们未必每一D字W序列后面都有个相应?#8217;’来结。如果直?q接Q不是sprintf q是strcat 肯定会导致非法内存操作,而strncat 也至要求第一个参数是个null-terminated-stringQ那该怎么办呢Q我们自然会惌v前面介绍打印整数和QҎ时可以指定宽度,字符?也一L。比如:
char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', 'N'};
如果Q?br /> sprintf(s, "%s%s", a1, a2); //Don't do that!
十有八九要出问题了。是否可以改成:
sprintf(s, "%7s%7s", a1, a2);
也没好到哪儿去,正确的应该是Q?br /> sprintf(s, "%.7s%.7s", a1, a2);//产生Q?ABCDEFGHIJKLMN"
q可以类比打印QҎ?#8221;%m.nf”Q在”%m.ns”中,m 表示占用宽度Q字W串长度不时补I格Q超Z则按照实际宽度打华ͼQn 才表CZ相应的字W串中最多取用的字符数。通常在打印字W串时m 没什么大用,q是点号后面的n 用的多。自Ӟ也可以前后都只取部分字符Q?br /> sprintf(s, "%.6s%.5s", a1, a2);//产生Q?ABCDEFHIJKL"
在许多时候,我们或许q希望这些格式控制符中用以指定长度信息的数字是动态的Q而不是静态指定的Q因多时候,E序要到q行时才会清楚到底需要取?W数l中的几个字W,q种动态的宽度/_ֺ讄功能在sprintf 的实C也被考虑CQsprintf 采用”*”来占用一个本来需要一个指定宽度或_ֺ的常数数字的位置Q同P而实际的宽度或精度就可以和其它被打印的变量一栯提供出来Q于是,上面的例?可以变成Q?br /> sprintf(s, "%.*s%.*s", 7, a1, 7, a2);
或者:
sprintf(s, "%.*s%.*s", sizeof(a1), a1, sizeof(a2), a2);
实际上,前面介绍的打印字W、整数、QҎ{都可以动态指定那些常量|比如Q?br /> sprintf(s, "%-*d", 4, 'A'); //产生"65 "
sprintf(s, "%#0*X", 8, 128); //产生"0X000080"Q?#"产生0X
sprintf(s, "%*.*f", 10, 2, 3.1415926); //产生" 3.14"
(4)打印地址信息
有时调试E序Ӟ我们可能x看某些变量或者成员的地址Q由于地址或者指针也不过是个32 位的敎ͼ你完全可以用打印无W号整数?#8221;%u”把他们打印出来:
sprintf(s, "%u", &i);
不过通常Zq是喜欢使用16 q制而不?0 q制来显CZ个地址Q?br /> sprintf(s, "%08X", &i);
然而,q些都是间接的方法,对于地址打印Qsprintf 提供了专门的”%p”Q?br /> sprintf(s, "%p", &i);
我觉得它实际上就相当于:
sprintf(s, "%0*x", 2 * sizeof(void *), &i);
(5)利用sprintf 的返回?/span>
较少有h注意printf/sprintf 函数的返回|但有时它却是有用的,spritnf q回了本ơ函数调?br /> 最l打印到字符~冲Z的字W数目。也是说每当一ơsprinf 调用l束以后Q你无须再调用一?br /> strlen 便已l知道了l果字符串的长度。如Q?br /> int len = sprintf(s, "%d", i);
对于正整数来_len 便等于整数i ?0 q制位数?br /> 下面的是个完整的例子Q?0 个[0, 100)之间的随机数Qƈ他们打印到一个字W数ls 中,
以逗号分隔开?br /> #include
#include
#include
int main() {
srand(time(0));
char s[64];
int offset = 0;
for(int i = 0; i < 10; i++) {
offset += sprintf(s + offset, "%d,", rand() % 100);
}
s[offset - 1] = '/n';//最后一个逗号换成换行W?br /> printf(s);
return 0;
}
设想当你从数据库中取Z条记录,然后希望把他们的各个字段按照某种规则q接成一个字
W串Ӟ可以用这U方法,从理ZԌ他应该比不断的strcat 效率高,因ؓstrcat 每次调用
都需要先扑ֈ最后的那个’’的位|,而在上面l出的例子中Q我们每ơ都利用sprintf q回值把q?br /> 个位|直接记下来了?br /> 使用sprintf 的常见问?br /> sprintf 是个变参函数Q用时l常出问题,而且只要出问题通常是能导致程序崩溃的内存?br /> 问错误,但好在由sprintf 误用D的问题虽然严重,却很Ҏ扑ևQ无非就是那么几U情况,?br /> 常用眼睛再把出错的代码多看几眼就看出来了?br /> ?? ~冲区溢?br /> W一个参数的长度太短了,没的_l个大点的地方吧。当然也可能是后面的参数的问
题,变参对应一定要l心Q而打印字W串Ӟ量使用”%.ns”的Ş式指定最大字W数?br /> ?? 忘记了第一个参?br /> 低得不能再低问题Q用printf 用得太惯了?/偶就常犯。:。(
?? 变参对应出问?br /> 通常是忘C提供对应某个格式W的变参Q导致以后的参数l统错位Q检查检查吧。尤
其是对应”*”的那些参敎ͼ都提供了吗?不要把一个整数对应一?#8221;%s”Q编译器会觉得你
ƺ她太甚了(~译器是obj 和exe 的妈妈,应该是个女的Q?PQ?br /> strftime
sprnitf q有个不错的表妹QstrftimeQ专门用于格式化旉字符串的Q用法跟她表哥很像,?br /> 是一大堆格式控制W,只是毕竟姑娘家心细Q她q要调用者指定缓冲区的最大长度,可能是ؓ
了在出现问题时可以推卸责d。这里D个例子:
time_t t = time(0);
//产生"YYYY-MM-DD hh:mm:ss"格式的字W串?br /> char s[32];
strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", localtime(&t));
sprintf 在MFC 中也能找C的知韻ICString::FormatQstrftime 在MFC 中自然也有她的同道:
CTime::FormatQ这一对由于从面向对象哪里得到了赞助,用以写出的代码更觉优雅?/span>
sprintf 用法ȝ(2009-08-25 09:36:24)标签Qit 分类QC++
sprintf,各U类型的数据够造成字符丌Ӏ?/span>
sprintf是个变参函数Qint sprintf(char *buffer,const char *format[,argument]...);除了前两个参数类型固定外Q后面可以接L多个参数Q而它的精华,则在W二个参敎ͼ格式化字W串上?/span>
printf和sprintf都用格式化字符串来指定串的格式Q在格式串内部 用一些以“Q?#8221;开头的格式说明W(format specificationQ来占据一个位|,在后边的变参列表中提供相应的变量Q最l函数就会用相应位置的变量来替代那个说明W,产生一个调用者想要的 字符丌Ӏ?/span>
一、格式化数字字符?/span>
sprintf最常见的应用之一莫过于把整数打印到字W串中,所以sprintf在大多数场合可以替代itoa.
%-8d 代表宽度八位Q左寚wQ没有负号ؓ叛_齐)Q整数的十进?/span>
%x写16q制 %X大写16q制
W号扩展问题Q参数压栈默认四字节Q即Q位16q制。应该让~译器做0扩展而不是符h展?/span>
如 sprintf(s,"%04X",(unsigned short)si);
%o 8q制格式化字W串?/span>
控制点数打印格式,使用格式W?%f"控制Q默认保留小数点后6位数字?/span>
%m.nf m表示打印的宽?n表示数点后的位?/span>
sprintf(s,"%m.nf",i)其中i 必须为Q点类型的
二、字W?ASCII码对?/span>
%c打印一个整敎ͼ可以看到整数所对应的ASCII?/span>
for(int i=32 ;i<127;i++)
{
printf("[%c]:%3d 0x%#04X/n",i,i,i);
}
#?X合用时自动ؓ16q制数增?#8220;0X”前缀?/span>
三、连接字W串
可以在许多场合替代strcatQsprintf能够一ơ连接多个字W串?/span>
%s可以参照点数控制的%m.n m表示宽度,n表示从相应的字符串中最多取用的字符敎ͼ通常m没什么用?/span>
对于动态的Q可以采用sprintf(s,"%.*s%.*s",7,a1,7,a2)或sprintf(s,"%.*s%.*s",sizeof(a1),a1,sizeof(a2),a2);
四、打印地址信息
有时调试E序Ӟ我们可能x看某些变量或者成员的地址Q由于地址或者指针也不过是个32 位的敎ͼ你完全可以用打印无W号整数?#8221;%u”把他们打印出来:
sprintf(s, "%u", &i);
不过通常Zq是喜欢使用16 q制而不?0 q制来显CZ个地址Q?br /> sprintf(s, "%08X", &i);
然而,q些都是间接的方法,对于地址打印Qsprintf 提供了专门的”%p”Q?br /> sprintf(s, "%p", &i);
我觉得它实际上就相当于:
sprintf(s, "%0*x", 2 * sizeof(void *), &i);
五、返回?/span>
q回了本ơ函数调用最l打印到字符~冲Z的字W数目?
六、strftime
专门用于格式化时间字W串。需调用者指定缓冲区的最大长度?/span>
strftime(s,sizeof(s),"%Y-%m-%d %H:%M:%S",localtime(&t));