整理:C++中sprintf()函数的使⽤详解
资料⼀
描述
C 库函数 int sprintf(char *str, const char *format, ...) 发送格式化输出到 str 所指向的字符串。
声明
下⾯是 sprintf() 函数的声明。
int sprintf(char*str,const char*format,...)
参数
str -- 这是指向⼀个字符数组的指针,该数组存储了 C 字符串。
format -- 这是字符串,包含了要被写⼊到字符串 str 的⽂本。它可以包含嵌⼊的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进⾏格式化。format 标签属性是 %[flags][width][.precision][length]specifier,具体讲解如下:
c字符
d 或 i有符号⼗进制整数
e使⽤ e 字符的科学科学记数法(尾数和指数)
E使⽤ E 字符的科学科学记数法(尾数和指数)
f⼗进制浮点数
g⾃动选择 %e 或 %f 中合适的表⽰法
G⾃动选择 %E 或 %f 中合适的表⽰法
o有符号⼋进制
s字符的字符串
u⽆符号⼗进制整数
x⽆符号⼗六进制整数
X⽆符号⼗六进制整数(⼤写字母)
p指针地址
n⽆输出
%字符
晏子使楚翻译-在给定的字段宽度内左对齐,默认是右对齐(参见 width ⼦说明符)。
+强制在结果之前显⽰加号或减号(+ 或 -),即正数前⾯会显⽰ + 号。默认
情况下,只有负数前⾯会显⽰⼀个 - 号。
(space)如果没有写⼊任何符号,则在该值前⾯插⼊⼀个空格。
#与 o、x 或 X 说明符⼀起使⽤时,⾮零值前⾯会分别显⽰ 0、0x 或 0X。
与 e、E 和 f ⼀起使⽤时,会强制输出包含⼀个⼩数点,即使后边没有数字
时也会显⽰⼩数点。默认情况下,如果后边没有数字时候,不会显⽰显⽰
⼩数点。
与 g 或 G ⼀起使⽤时,结果与使⽤ e 或 E 时相同,但是尾部的零不会被移
除。
0在指定填充 padding 的数字左边放置零(0),⽽不是空格(参见 width ⼦
说明符)。
(number)要输出的字符的最⼩数⽬。如果输出的值短于该数,结果会⽤空格填充。
如果输出的值长于该数,结果不会被截断。
*宽度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格
式化的参数之前。
.number 对于整数说明符(d 、i 、o 、u 、x 、X ):precision 指定了要写⼊的数字的
最⼩位数。如果写⼊的值短于该数,结果会⽤前导零来填充。如果写⼊的
值长于该数,结果不会被截断。精度为 0 意味着不写⼊任何字符。
对于 e 、E 和 f 说明符:要在⼩数点后输出的⼩数位数。
对于 g 和 G 说明符:要输出的最⼤有效位数。
对于 s: 要输出的最⼤字符数。默认情况下,所有字符都会被输出,直到遇
到末尾的空字符。
对于 c 类型:没有任何影响。
当未指定任何精度时,默认为 1。如果指定时不带有⼀个显式值,则假定为
翻译中文
0。
.*精度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格
式化的参数之前。
h
described
参数被解释为短整型或⽆符号短整型(仅适⽤于整数说明符:i 、d 、o 、u 、x 和 X )。l
参数被解释为长整型或⽆符号长整型,适⽤于整数说明符(i 、d 、o 、u 、x 和 X )及说明符 c (表⽰⼀个宽字符)和 s (表⽰宽字符字符串)。L 参数被解释为长双精度型(仅适⽤于浮点数说明符:e 、E 、f 、g 和 G )。
附加参数 -- 根据不同的 format 字符串,函数可能需要⼀系列的附加参数,每个参数包含了⼀个要被插⼊的值,替换了 format 参数中指定的每个% 标签。参数的个数应与 % 标签的个数相同。
返回值
如果成功,则返回写⼊的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回⼀个负数。
实例
下⾯的实例演⽰了 sprintf() 函数的⽤法。
让我们编译并运⾏上⾯的程序,这将产⽣以下结果:
资料⼆
在将各种类型的数据构造成字符串时,sprintf 的强⼤功能很少会让你失望。由于sprintf 跟printf 在⽤法上⼏乎⼀样,只是打印的⽬的地不同⽽已,前者打印到字符串中,后者则直接在命令⾏上输出。这也导致sprintf ⽐printf 有⽤得多。
sprintf 是个变参函数,定义如下:
int sprintf( char *buffer, const char *format [, argument] ... );
除了前两个参数类型固定外,后⾯可以接任意多个参数。⽽它的精华,显然就在第⼆个参数:
(1)格式化字符串上。
printf 和sprintf 都使⽤格式化字符串来指定串的格式,在格式串内部使⽤⼀些以“%”开头的格式说明符(format specifications)来占据⼀个位置,在后边的变参列表中提供相应的变量,最终函数就会⽤相应位置的变量来替代那个说明符,产⽣⼀个调⽤者想要的字符串。
格式化数字字符串
sprintf 最常见的应⽤之⼀莫过于把整数打印到字符串中,所以,spritnf 在⼤多数场合可以替代itoa。
如:
//把整数123 打印成⼀个字符串保存在s 中。
sprintf(s, "%d", 123); //产⽣"123"
可以指定宽度,不⾜的左边补空格:sprintf(s, "%8d%8d", 123, 4567); //产⽣:" 123 4567"
#include <stdio.h>#include <math.h>
int main (){ char str [80];
sprintf (str , "Pi 的值 = %f", M_PI ); puts (str ); return (0);}
Pi 的值 = 3.141593
当然也可以左对齐:
sprintf(s, "%-8d%8d", 123, 4567); //产⽣:"123 4567"
也可以按照16 进制打印:
sprintf(s, "%8x", 4567); //⼩写16 进制,宽度占8 个位置,右对齐
nd nudessprintf(s, "%-8X", 4568); //⼤写16 进制,宽度占8 个位置,左对齐
这样,⼀个整数的16 进制字符串就很容易得到,但我们在打印16 进制内容时,通常想要⼀种左边补0 的等宽格式,那该怎么做呢?很简单,在表⽰宽度的数字前⾯加个0 就可以了。
sprintf(s, "%08X", 4567); //产⽣:"000011D7"
上⾯以”%d”进⾏的10 进制打印同样也可以使⽤这种左边补0 的⽅式。
这⾥要注意⼀个符号扩展的问题:⽐如,假如我们想打印短整数(short)-1 的内存16 进制表⽰形式,在Win32 平台上,⼀个short 型占2 个字节,所以我们⾃然希望⽤4 个16 进制数字来打印它:
short si = -1;
秋水翻译sprintf(s, "%04X", si);
产⽣“FFFFFFFF”,怎么回事?因为spritnf 是个变参函数,除了前⾯两个参数之外,后⾯的参数都不是类型安全的,函数更没有办法仅仅通过⼀个“%X”就能得知当初函数调⽤前参数压栈时被压进来的到底是个4 字节的整数还是个2 字节的短整数,所以采取了统⼀4 字节的处理⽅式,导致参数压栈时做了符号扩展,扩展成了32 位的整数-1,打印时4 个位置不够了,就把32 位整数-1 的8 位16 进制都打印出来了。
如果你想看si 的本来⾯⽬,那么就应该让编译器做0 扩展⽽不是符号扩展(扩展时⼆进制左边补0 ⽽不是补符号位):
sprintf(s, "%04X", (unsigned short)si);
就可以了。或者:
unsigned short si = -1;
sprintf(s, "%04X", si);
sprintf 和printf 还可以按8 进制打印整数字符串,使⽤”%o”。注意8 进制和16 进制都不会打
印出负数,都是⽆符号的,实际上也就是变量的内部编码的直接的16 进制或8 进制表⽰。
控制浮点数打印格式
浮点数的打印和格式控制是sprintf 的⼜⼀⼤常⽤功能,浮点数使⽤格式符”%f”控制,默认保
留⼩数点后6 位数字,⽐如:
sprintf(s, "%f", 3.1415926); //产⽣"3.141593"
但有时我们希望⾃⼰控制打印的宽度和⼩数位数,这时就应该使⽤:”%m.nf”格式,其中m 表
⽰打印的宽度,n 表⽰⼩数点后的位数。⽐如:
sprintf(s, "%10.3f", 3.1415626); //产⽣:" 3.142"
sprintf(s, "%-10.3f", 3.1415626); //产⽣:"3.142 "
sprintf(s, "%.3f", 3.1415626); //不指定总宽度,产⽣:"3.142"
注意⼀个问题,你猜
int i = 100;
sprintf(s, "%.2f", i);
会打出什么东东来?“100.00”?对吗?⾃⼰试试就知道了,同时也试试下⾯这个:
sprintf(s, "%.2f", (double)i);
第⼀个打出来的肯定不是正确结果,原因跟前⾯提到的⼀样,参数压栈时调⽤者并不知道跟i相对应的
格式控制符是个”%f”。⽽函数执⾏时函数本⾝则并不知道当年被压⼊栈⾥的是个整数,于是可怜的保存整数i 的那4 个字节就被不由分说地强⾏作为浮点数格式来解释了,整个乱套了。不过,如果有⼈有兴趣使⽤⼿⼯编码⼀个浮点数,那么倒可以使⽤这种⽅法来检验⼀下你⼿⼯编排的结果是否正确。
资料三
int sprintf( char *buffer, const char *format [, argument] ... );
radiofrequency
除了前两个参数类型固定外,后⾯可以接任意多个参数。⽽它的精华,显然就在第⼆个参数:格式化字符串上。 printf和sprintf都使⽤格式化字符串来指定串的格式,在格式串内部使⽤⼀些以“%”开头的格式说明符(format specifications)来占据⼀个位置,在后边的变参列表中提供相应的变量,最终函数就会⽤相应位置的变量来替代那个说明符,产⽣⼀个调⽤者想要的字符串。 1. 格式化数字字符串 sprintf最常见的应⽤之⼀莫过于把整数打印到字符串中,所以,spritnf在⼤多数场合可以替代itoa。如:
//把整数123打印成⼀个字符串保存在s中。
sprintf(s, "%d", 123); //产⽣"123" 可以指定宽度,不⾜的左边补空格:
sprintf(s, "%8d%8d", 123, 4567); //产⽣:" 123 4567" 当然也可以左对齐:
android marketsprintf(s, "%-8d%8d", 123, 4567); //产⽣:"123 4567" 也可以按照16进制打印:
sprintf(s, "%8x", 4567); //⼩写16进制,宽度占8个位置,右对齐
sprintf(s, "%-8X", 4568); //⼤写16进制,宽度占8个位置,左对齐这样,⼀个整数的16进制字符串就很容易得到,但我们在打印16进制内容时,通常想要⼀种左边补0的等宽格式,那该怎么做呢?很简单,在表⽰宽度的数字前⾯加个0就可以了。
sprintf(s, "%08X", 4567); //产⽣:"000011D7" 上⾯以”%d”进⾏的10进制打印同样也可以使⽤这种左边补0的⽅式。这⾥要注意⼀个符号扩展的问题:⽐如,假如我们想打印短整数(short)-1的内存16进制表⽰形式,在Win32平台上,⼀个short型占2个字节,所以我们⾃然希望⽤4个16进制数字来打印它:
short si = -1;
sprintf(s, "%04X", si); 产⽣“FFFFFFFF”,怎么回事?因为spritnf是个变参函数,除了前⾯两个参数之外,后⾯的参数都不是类型安全的,函数更没有办法仅仅通过⼀个 “%X”就能得知当初函数调⽤前参数压栈时被压进来的到底是个4字节的整数还是个2字节的短整数,所以采取了统⼀4字节的处理⽅式,导致参数压栈时做了符号扩展,扩展成了32位的整数-1,打印时4个位置不够了,就把32位整数-1的8
位16进制都打印出来了。如果你想看si的本来⾯⽬,那么就应该让编译器做0扩展⽽不是符号扩展(扩展时⼆进制左边补0⽽不是补符号位):
sprintf(s, "%04X", (unsigned short)si); 就可以了。或者:
unsigned short si = -1;
the flavor of lifesprintf(s, "%04X", si); sprintf和printf还可以按8进制打印整数字符串,使⽤”%o”。注意8进制和16进制都不会打印出负数,都是⽆符号的,实际上也就是变量的内部编码的直接的16进制或8进制表⽰。 2. 控制浮点数打印格式浮点数的打印和格式控制是sprintf的⼜⼀⼤常⽤功能,浮点数使⽤格式符”%f”控制,默认保留⼩数点后6位数字,⽐如:
sprintf(s, "%f", 3.1415926); //产⽣"3.141593" 但有时我们希望⾃⼰控制打印的宽度和⼩数位数,这时就应该使⽤:”%m.nf”格式,其中m表⽰打印的宽度,n表⽰⼩数点后的位数。⽐如:
sprintf(s, "%10.3f", 3.1415626); //产⽣:" 3.142"
sprintf(s, "%-10.3f", 3.1415626); //产⽣:"3.142 "
sprintf(s, "%.3f", 3.1415626); //不指定总宽度,产⽣:"3.142" 注意⼀个问题,你猜
int i = 100;
sprintf(s, "%.2f", i); 会打出什么东东来?“100.00”?对吗?⾃⼰试试就知道了,同时也试试下⾯这个:
sprintf(s, "%.2f", (double)i); 第⼀个打出来的肯定不是正确结果,原因跟前⾯提到的⼀样,参数压栈时调⽤者并不知道跟i相对应的格式控制符是个”%f”。⽽函数执⾏时函数本⾝则并不知道当年被压⼊栈⾥的是个整数,于是可怜的保存整数i的那4个字节就被不由分说地强⾏作为浮点数格式来解释了,整个乱套了。不过,如果有⼈有兴趣使⽤⼿⼯编码⼀个浮点数,那么倒可以使⽤这种⽅法来检验⼀下你⼿⼯编排的结果是否正确。J 字
符/Ascii码对照我们知道,在C/C++语⾔中,char也是⼀种普通的scalable类型,除了字长之外,它与short,int,long这些类型没有本质区别,只不过被⼤家习惯⽤来表⽰字符和字符串⽽已。(或许当年该把这个类型叫做“byte”,然后现在就可以根据实际情况,使⽤byte或short来把char 通过typedef定义出来,这样更合适些)于是,使⽤”%d”或者”%x”打印⼀个字符,便能得出它的10进制或16进制的ASCII码;反过来,使⽤”%c”打印⼀个整数,便可以看到它所对应的 ASCII字符。
#include <stdio.h>
#include <stdlib.h>
int main()
{
char str1[10] ={0, };
char str2[10] ={0, };
int ret1=0,ret2=0;
ret1=snprintf(str1, sizeof(str1), "%s", "abc");
ret2=snprintf(str2, 4, "%s", "aaabbbccc");
printf("aaabbbccc length=%d/n", strlen("aaabbbccc"));
printf("str1=%s,ret1=%d/n", str1, ret1);
printf("str2=%s,ret2=%d/n", str2, ret2);
门罗宣言return 0;
}
[root] /root/lindatest
$ ./test
aaabbbccc length=9
str1=abc,ret1=3
zeystr2=aaa,ret2=9
解释SIZE:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char dst1[10] ={0, },dst2[10] ={0, };
char src1[10] ="aaa",src2[15] ="aaabbbcccddd";
int size=sizeof(dst1);
int ret1=0, ret2=0;
ret1=snprintf(dst1, size, "str :%s", src1);
ret2=snprintf(dst2, size, "str :%s", src2);
printf("sizeof(dst1)=%d, src1=%s, /"str :%%s/"=%s%s, dst1=%s, ret1=%d/n", sizeof(dst1), src1, "str :", src1, dst1, ret1);
printf("sizeof(dst2)=%d, src2=%s, /"str :%%s/"=%s%s, dst2=%s, ret2=%d/n", sizeof(dst2), src2, "str :", src2, dst2, ret2);
return 0;
}
root] /root/lindatest
$ ./test
sizeof(dst1)=10, src1=aaa, "str :%s"=str :aaa, dst1=str :aaa, ret1=8
sizeof(dst2)=10, src2=aaabbbcccddd, "str :%s"=str :aaabbbcccddd, dst2=str :aaab, ret2=17
补充⼀下,snprintf的返回值是欲写⼊的字符串长度,⽽不是实际写⼊的字符串度。如:
char test[8];
int ret = snprintf(test,5,"1234567890");
printf("%d|%s/n",ret,test);
运⾏结果为:
10|1234
数原型:
int snprintf(char *str, size_t size, const char *format, ...);
size 的作⽤就是限制往str写⼊不超过size个字节(包括了结尾的'/0')。
因为sprintf()函数如果成功的话,返回成功写⼊的字节数(字符数),我就⼀直以为snprintf()函数也是如此,也就是snprintf()函数不会返回⼤于size的整数。
看下⾯⼀段⼿册内容:
The functions snprintf() and vsnprintf() do not write more than size bytes (including the trailing ’/0’). If the output was truncated due to this limit then the return value is the number of characters (not including the trailing ’/0’) which would have been written to the final string if enough space had been available. Thus, a return value of size or more means that the output was truncated.
如果输出因为size的限制⽽被截断,返回值将是“如果有⾜够空间存储,所应能输出的字符数(不包括字符串结尾的'/0')”,这个值和size相等或者⽐size ⼤!也就是说,如果可以写⼊的字符串是"012345678
9ABCDEF" 共16位,但是size限制了是10,这样 snprintf() 的返回值将会是16⽽不是 10 !