整理: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,具体讲解如下:
specifier(说明符) 输出
c 字符
d 或 i 有符号十进制整数
e 使用 e 字符的科学科学记数法(尾数和指数)
E 使用 E 字符的科学科学记数法(尾数和指数)
f 十进制浮点数
g 自动选择 %e 或 %f 中合适的表示法
G 自动选择 %E 或 %f 中合适的表示法
o 有符号八进制
s 字符的字符串
u 无符号十进制整数
x 无符号十六进制整数
X 无符号十六进制整数(大写字母)
p 指针地址
n 无输出
% 字符

flags(标识) 描述
- 在给定的字段宽度内左对齐,默认是右对齐(参见 width 子说明符)。
+ 强制在结果之前显示加号或减号(+ 或 -),即正数前面会显示 + 号。默认情况下,只有负数前面会显示一个 - 号。
(space) 如果没有写入任何符号,则在该值前面插入一个空格。
# 与 o、x 或 X 说明符一起使用时,非零值前面会分别显示 0、0x 或 0X。
与 e、E 和 f 一起使用时,会强制输出包含一个小数点,即使后边没有数字时也会显示小数点。默认情况下,如果后边没有数字时候,不会显示显示小数点。
与 g 或 G 一起使用时,结果与使用 e 或 E 时相同,但是尾部的零不会被移除。
0 在指定填充 padding 的数字左边放置零(0),而不是空格(参见 width 子说明符)。

width(宽度) 描述
(number) 要输出的字符的最小数目。如果输出的值短于该数,结果会用空格填充。如果输出的值长于该数,结果不会被截断。
* 宽度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。

.precision(精度) 描述
.number 对于整数说明符(d、i、o、u、x、X):precision 指定了要写入的数字的最小位数。如果写入的值短于该数,结果会用前导零来填充。如果写入的值长于该数,结果不会被截断。精度为 0 意味着不写入任何字符。
对于 e、E 和 f 说明符:要在小数点后输出的小数位数。
对于 g 和 G 说明符:要输出的最大有效位数。
对于 s: 要输出的最大字符数。默认情况下,所有字符都会被输出,直到遇到末尾的空字符。
对于 c 类型:没有任何影响。
当未指定任何精度时,默认为 1。如果指定时不带有一个显式值,则假定为 0。
.* 精度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。

length(长度) 描述
h 参数被解释为短整型或无符号短整型(仅适用于整数说明符:i、d、o、u、x 和 X)。
l 参数被解释为长整型或无符号长整型,适用于整数说明符(i、d、o、u、x 和 X)及说明符 c(表示一个宽字符)和 s(表示宽字符字符串)。
L 参数被解释为长双精度型(仅适用于浮点数说明符:e、E、f、g 和 G)。
  • 附加参数 -- 根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。

返回值

如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。

实例

下面的实例演示了 sprintf() 函数的用法。

#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 的强大功能很少会让你失望。由于sprintf 跟printf 在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,后者则直接在命令行上输出。这也导致sprintf 比printf 有用得多。

sprintf 是个变参函数,定义如下:
int sprintf( char *buffer, const char *format [, argument] ... );
除了前两个参数类型固定外,后面可以接任意多个参数。而它的精华,显然就在第二个参数:
(1)格式化字符串上。
printfsprintf 都使用格式化字符串来指定串的格式,在格式串内部使用一些以“%”开头的格式说明符(format specifications)来占据一个位置,在后边的变参列表中提供相应的变量,最终函数就会用相应位置的变量来替代那个说明符,产生一个调用者想要的字符串。
格式化数字字符串
sprintf 最常见的应用之一莫过于把整数打印到字符串中,所以,spritnf 在大多数场合可以替代itoa。
如:
//把整数123 打印成一个字符串保存在s 中。
sprintf(s, "%d", 123); //产生"123"
可以指定宽度,不足的左边补空格:
sprintf(s, "%8d%8d", 123, 4567); //产生:" 123 4567"
当然也可以左对齐:
sprintf(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;
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] ... );

除了前两个参数类型固定外,后面可以接任意多个参数。而它的精华,显然就在第二个参数:格式化字符串上。 printf和sprintf都使用格式化字符串来指定串的格式,在格式串内部使用一些以“%”开头的格式说明符(format specifications)来占据一个位置,在后边的变参列表中提供相应的变量,最终函数就会用相应位置的变量来替代那个说明符,产生一个调用者想要 的字符串。 1. 格式化数字字符串 sprintf最常见的应用之一莫过于把整数打印到字符串中,所以,spritnf在大多数场合可以替代itoa。如:

//把整数123打印成一个字符串保存在s中。

sprintf(s, "%d", 123); //产生"123" 可以指定宽度,不足的左边补空格:

sprintf(s, "%8d%8d", 123, 4567); //产生:" 123 4567" 当然也可以左对齐:

sprintf(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;

sprintf(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字符。


int snprintf(char *restrict buf, size_t n, const char * restrict  format, ...);

函数说明:最多从源串中拷贝n-1个字符到目标串中,然后再在后面加一个0。所以如果目标串的大小为n 的话,将不会溢出。

函数返回值:若成功则返回欲写入的字符串长度,若出错则返回负值。

Result1(推荐的用法)

#include <stdio.h>
#include <stdlib.h>

int main()
{
     char str[10]={0,};
     snprintf(str, sizeof(str ) , "0123456789012345678");
     printf("str=%s/n", str);
     return 0;
}

root] /root/lindatest
$ ./test 
str=012345678

Result2:(不推荐使用)

#include <stdio.h>
#include <stdlib.h>

int main()
{
    char str[10]={0, };
    snprintf(str, 18, "0123456789012345678");
    printf("str=%s/n", str);
    return 0;
}

root] /root/lindatest
$ ./test
str=01234567890123456

snprintf函数返回值的测试:

#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
str2=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大!也就是说,如果可以写入的字符串是"0123456789ABCDEF" 共16位,但是size限制了是10,这样 snprintf() 的返回值将会是16 而不是 10 
 
上面的内容还说,如果返回值等于或者大于size,则表明输出字符串被截断了(truncated)。



资料四

在将各种类型的数据构造成字符串时,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"
  当然也可以左对齐:
  sprintf(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;
  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 个字节就被不由分说地强行作为浮点数格式来解释了,整个乱套了。不过,如果有人有兴趣使用手工编码一个浮点数,那么倒可以使用这种方法来检验一下你手工编排的结果是否正确。




资料五


将字串格式化命令。sprintf 是个变参函数,使用时经常出问题,而且只要出问题通常就是能导致程序崩溃的内存访 问错误,但好在由sprintf 误用导致的问题虽然严重,却很容易找出,无非就是那么几种情况,通 常用眼睛再把出错的代码多看几眼就看出来了。

  sprintf 将字串格式化。

  在头文件 #include<stdio.h

  >中

  语法: int sprintf(string format, mixed [args]...);

  返回值:字符串长度(strlen)

  sprintf格式的规格如下所示。[]中的部分是可选的。

  %[指定参数$][标识符][宽度][.精度]指示符

  若想输出`%'本身时, 请这样`%%'处理。

  1. 处理字符方向。负号时表示从后向前处理。

  2. 填空字元。 0 的话表示空格填 0;空格是内定值,表示空格就放着。

  3. 字符总宽度。为最小宽度。

  4. 精确度。指在小数点后的浮点数位数。

  =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

  转换字符

  =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

  %% 印出百分比符号,不转换。

  %c 整数转成对应的 ASCII 字元。

  %d 整数转成十进位。

  %f 倍精确度数字转成浮点数。

  %o 整数转成八进位。

  %s 整数转成字串。

  %x 整数转成小写十六进位。

  %X 整数转成大写十六进位。

  =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

  <?

  $money = 123.1

  $formatted = sprintf ("%06.2f", $money); // 此时变数 $ formatted 值为 "123.10"

  $formatted = sprintf ("%08.2f", $money); // 此时变数 $ formatted 值为 "00123.10"

  $formatted = sprintf ("%-08.2f", $money); // 此时变数 $ formatted 值为 "123.1000"

  $formatted = sprintf ("%.2f%%", 0.95 * 100); // 格式化为百分比

  ?>

  ¢%08.2f 解释:

  %开始符

  0是 "填空字元" 表示,如果长度不足时就用0来填满。

  8格式化后总长度

  2f小数位长度,即2位

  ¢第3行值为"00123.10" 解释:

  因为2f是(2位)+小数点符号(1)+前面123(3位)=6位,总长度为8位,故前面用[填空字元]0表示,即00123.10

  ¢第4行值为"123.1000" 解释:

  -号为反向操作,然后填空字元0添加在最后面了

  /********************************************************

  以下选自《CSDN 社区电子杂志——C/C++杂志》

  *********************************************************/

  在将各种类型的数据构造成字符串时,sprintf 的强大功能很少会让你失望。由于sprintf 跟printf 在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,后者则直接在命令行上输出。这也导致sprintf 比printf 有用得多。

  sprintf 是个变参函数,定义如下:

  int sprintf( char *buffer, const char *format [, argument] ... );

  除了前两个参数类型固定外,后面可以接任意多个参数。而它的精华,显然就在第二个参数:

  格式化字符串上。

  printf 和sprintf 都使用格式化字符串来指定串的格式,在格式串内部使用一些以“%”开头的格式说明符(format specifications)来占据一个位置,在后边的变参列表中提供相应的变量,最终函数就会用相应位置的变量来替代那个说明符,产生一个调用者想要的字符串。

  格式化数字字符串

  sprintf 最常见的应用之一莫过于把整数打印到字符串中,所以,spritnf 在大多数场合可以替代

  itoa。

  如:

  //把整数123 打印成一个字符串保存在s 中。

  sprintf(s, "%d", 123); //产生"123"

  可以指定宽度,不足的左边补空格:

  sprintf(s, "%8d%8d", 123, 4567); //产生:" 123 4567"

  当然也可以左对齐:

  sprintf(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;

  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 个字节就被不由分说地强行作为浮点数格式来解释了,整个乱套了。不过,如果有人有兴趣使用手工编码一个浮点数,那么倒可以使用这种方法来检验一下你手工编排的结果是否正确。

  字符/Ascii 码对照

  我们知道,在C/C++语言中,char 也是一种普通的scalable 类型,除了字长之外,它与short,

  int,long 这些类型没有本质区别,只不过被大家习惯用来表示字符和字符串而已。(或许当年该把

  这个类型叫做“byte”,然后现在就可以根据实际情况,使用byte 或short 来把char 通过typedef 定义出来,这样更合适些)于是,使用”%d”或者”%x”打印一个字符,便能得出它的10 进制或16 进制的ASCII 码;反过来,使用”%c”打印一个整数,便可以看到它所对应的ASCII 字符。以下程序段把所有可见字符的ASCII 码对照表打印到屏幕上(这里采用printf,注意”#”与”%X”合用时自动为16 进制数增加”0X”前缀):

  for(int i = 32; i < 127; i++) {

  printf("[ %c ]: %3d 0x%#04X/n", i, i, i);

  }

连接字符串

  sprintf 的格式控制串中既然可以插入各种东西,并最终把它们“连成一串”,自然也就能够连

  接字符串,从而在许多场合可以替代strcat,但sprintf 能够一次连接多个字符串(自然也可以同时

  在它们中间插入别的内容,总之非常灵活)。比如:

  char* who = "I";

  char* whom = "CSDN";

  sprintf(s, "%s love %s.", who, whom); //产生:"I love CSDN. "

  strcat 只能连接字符串(一段以’’结尾的字符数组或叫做字符缓冲,null-terminated-string),但有时我们有两段字符缓冲区,他们并不是以 ’’结尾。比如许多从第三方库函数中返回的字符数组,从硬件或者网络传输中读进来的字符流,它们未必每一段字符序列后面都有个相应的’’来结尾。如果直接连接,不管是sprintf 还是strcat 肯定会导致非法内存操作,而strncat 也至少要求第一个参数是个null-terminated-string,那该怎么办呢?我们自然会想起前面介绍打印整数和浮点数时可以指定宽度,字符串也一样的。比如:

  char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};

  char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', 'N'};

  如果:

  sprintf(s, "%s%s", a1, a2); //Don't do that!

  十有八九要出问题了。是否可以改成:

  sprintf(s, "%7s%7s", a1, a2);

  也没好到哪儿去,正确的应该是:

  sprintf(s, "%.7s%.7s", a1, a2);//产生:"ABCDEFGHIJKLMN"

  这可以类比打印浮点数的”%m/nf”,在”%m.ns”中,m 表示占用宽度(字符串长度不足时补空格,超出了则按照实际宽度打印),n 才表示从相应的字符串中最多取用的字符数。通常在打印字符串时m 没什么大用,还是点号后面的n 用的多。自然,也可以前后都只取部分字符:

  sprintf(s, "%.6s%.5s", a1, a2);//产生:"ABCDEFHIJKL"

  在许多时候,我们或许还希望这些格式控制符中用以指定长度信息的数字是动态的,而不是静态指定的,因为许多时候,程序要到运行时才会清楚到底需要取字符数组中的几个字符,这种动态的宽度/精度设置功能在sprintf 的实现中也被考虑到了,sprintf 采用”*”来占用一个本来需要一个指定宽度或精度的常数数字的位置,同样,而实际的宽度或精度就可以和其它被打印的变量一样被提供出来,于是,上面的例子可以变成:

  sprintf(s, "%.*s%.*s", 7, a1, 7, a2);

  或者:

  sprintf(s, "%.*s%.*s", sizeof(a1), a1, sizeof(a2), a2);

  实际上,前面介绍的打印字符、整数、浮点数等都可以动态指定那些常量值,比如:

  sprintf(s, "%-*d", 4, 'A'); //产生"65 "

  sprintf(s, "%#0*X", 8, 128); //产生"0X000080","#"产生0X

  sprintf(s, "%*.*f", 10, 2, 3.1415926); //产生" 3.14"

  打印地址信息

  有时调试程序时,我们可能想查看某些变量或者成员的地址,由于地址或者指针也不过是个32 位的数,你完全可以使用打印无符号整数的”%u”把他们打印出来:

  sprintf(s, "%u", &i);

  不过通常人们还是喜欢使用16 进制而不是10 进制来显示一个地址:

  sprintf(s, "%08X", &i);

  然而,这些都是间接的方法,对于地址打印,sprintf 提供了专门的”%p”:

  sprintf(s, "%p", &i);

  我觉得它实际上就相当于:

  sprintf(s, "%0*x", 2 * sizeof(void *), &i);

  利用sprintf 的返回值

  较少有人注意printf/sprintf 函数的返回值,但有时它却是有用的,spritnf 返回了本次函数调用

  最终打印到字符缓冲区中的字符数目。也就是说每当一次sprinf 调用结束以后,你无须再调用一次

  strlen 便已经知道了结果字符串的长度。如:

  int len = sprintf(s, "%d", i);

  对于正整数来说,len 便等于整数i 的10 进制位数。

  下面的是个完整的例子,产生10 个[0, 100)之间的随机数,并将他们打印到一个字符数组s 中,

  以逗号分隔开。

  #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';//将最后一个逗号换成换行符。

  printf(s);

  return 0;

  }

  设想当你从数据库中取出一条记录,然后希望把他们的各个字段按照某种规则连接成一个字

  符串时,就可以使用这种方法,从理论上讲,他应该比不断的strcat 效率高,因为strcat 每次调用

  都需要先找到最后的那个’’的位置,而在上面给出的例子中,我们每次都利用sprintf 返回值把这

  个位置直接记下来了。

  MSDN中例子:

  // crt_sprintf.c// compile with: /W3// This program uses sprintf to format various// data and place them in the string named buffer.

  #include <stdio.h>

  int main( void )

  {

  char buffer[200], s[] = "computer", c = 'l';

  int i = 35, j;

  float fp = 1.7320534f; // Format and print various data:

  j = sprintf( buffer, " String: %s/n", s ); // C4996

  j += sprintf( buffer + j, " Character: %c/n", c ); // C4996

  j += sprintf( buffer + j, " Integer: %d/n", i ); // C4996

  j += sprintf( buffer + j, " Real: %f/n", fp );// C4996

  // Note: sprintf is deprecated; consider using sprintf_s instead

  printf( "Output:/n%s/ncharacter count = %d/n", buffer, j );

  }

  Copy

  Output:

  String: computer

  Character: l

  Integer: 35

  Real: 1.732053

  character count = 79

  使用sprintf 的常见问题

  sprintf 是个变参函数,使用时经常出问题,而且只要出问题通常就是能导致程序崩溃的内存访

  问错误,但好在由sprintf 误用导致的问题虽然严重,却很容易找出,无非就是那么几种情况,通

  常用眼睛再把出错的代码多看几眼就看出来了。

  ?? 缓冲区溢出

  第一个参数的长度太短了,没的说,给个大点的地方吧。当然也可能是后面的参数的问

  题,建议变参对应一定要细心,而打印字符串时,尽量使用”%.ns”的形式指定最大字符数。

  ?? 忘记了第一个参数

  低级得不能再低级问题,用printf 用得太惯了。//偶就常犯。:。(

  ?? 变参对应出问题

  通常是忘记了提供对应某个格式符的变参,导致以后的参数统统错位,检查检查吧。尤

  其是对应”*”的那些参数,都提供了吗?不要把一个整数对应一个”%s”,编译器会觉得你

  欺她太甚了(编译器是obj 和exe 的妈妈,应该是个女的,:P)。

  strftime

  sprnitf 还有个不错的表妹:strftime,专门用于格式化时间字符串的,用法跟她表哥很像,也

  是一大堆格式控制符,只是毕竟小姑娘家心细,她还要调用者指定缓冲区的最大长度,可能是为

  了在出现问题时可以推卸责任吧。这里举个例子:

  time_t t = time(0);

  //产生"YYYY-MM-DD hh:mm:ss"格式的字符串。

  char s[32];

  strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", localtime(&t));

  sprintf 在MFC 中也能找到他的知音:CString::Format,strftime 在MFC 中自然也有她的同道:

  CTime::Format,这一对由于从面向对象哪里得到了赞助,用以写出的代码更觉优雅。



资料六


在将各种类型的数据构造成字符串时,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"
  当然也可以左对齐:
  sprintf(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;
  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 个字节就被不由分说地强行作为浮点数格式来解释了,整个乱套了。不过,如果有人有兴趣使用手工编码一个浮点数,那么倒可以使用这种方法来检验一下你手工编排的结果是否正确。
  

    (2)字符/Ascii 码对照

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


  (3)连接字符串

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


  (4)打印地址信息

  有时调试程序时,我们可能想查看某些变量或者成员的地址,由于地址或者指针也不过是个32 位的数,你完全可以使用打印无符号整数的”%u”把他们打印出来:
  sprintf(s, "%u", &i);
  不过通常人们还是喜欢使用16 进制而不是10 进制来显示一个地址:
  sprintf(s, "%08X", &i);
  然而,这些都是间接的方法,对于地址打印,sprintf 提供了专门的”%p”:
  sprintf(s, "%p", &i);
  我觉得它实际上就相当于:
  sprintf(s, "%0*x", 2 * sizeof(void *), &i);


  (5)利用sprintf 的返回值

  较少有人注意printf/sprintf 函数的返回值,但有时它却是有用的,spritnf 返回了本次函数调用
  最终打印到字符缓冲区中的字符数目。也就是说每当一次sprinf 调用结束以后,你无须再调用一次
  strlen 便已经知道了结果字符串的长度。如:
  int len = sprintf(s, "%d", i);
  对于正整数来说,len 便等于整数i 的10 进制位数。
  下面的是个完整的例子,产生10 个[0, 100)之间的随机数,并将他们打印到一个字符数组s 中,
  以逗号分隔开。
  #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';//将最后一个逗号换成换行符。
  printf(s);
  return 0;
  }
  设想当你从数据库中取出一条记录,然后希望把他们的各个字段按照某种规则连接成一个字
  符串时,就可以使用这种方法,从理论上讲,他应该比不断的strcat 效率高,因为strcat 每次调用
  都需要先找到最后的那个’’的位置,而在上面给出的例子中,我们每次都利用sprintf 返回值把这
  个位置直接记下来了。
  使用sprintf 的常见问题
  sprintf 是个变参函数,使用时经常出问题,而且只要出问题通常就是能导致程序崩溃的内存访
  问错误,但好在由sprintf 误用导致的问题虽然严重,却很容易找出,无非就是那么几种情况,通
  常用眼睛再把出错的代码多看几眼就看出来了。
  ?? 缓冲区溢出
  第一个参数的长度太短了,没的说,给个大点的地方吧。当然也可能是后面的参数的问
  题,建议变参对应一定要细心,而打印字符串时,尽量使用”%.ns”的形式指定最大字符数。
  ?? 忘记了第一个参数
  低级得不能再低级问题,用printf 用得太惯了。//偶就常犯。:。(
  ?? 变参对应出问题
  通常是忘记了提供对应某个格式符的变参,导致以后的参数统统错位,检查检查吧。尤
  其是对应”*”的那些参数,都提供了吗?不要把一个整数对应一个”%s”,编译器会觉得你
  欺她太甚了(编译器是obj 和exe 的妈妈,应该是个女的,:P)。
  strftime
  sprnitf 还有个不错的表妹:strftime,专门用于格式化时间字符串的,用法跟她表哥很像,也
  是一大堆格式控制符,只是毕竟小姑娘家心细,她还要调用者指定缓冲区的最大长度,可能是为
  了在出现问题时可以推卸责任吧。这里举个例子:
  time_t t = time(0);
  //产生"YYYY-MM-DD hh:mm:ss"格式的字符串。
  char s[32];
  strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", localtime(&t));
  sprintf 在MFC 中也能找到他的知音:CString::Format,strftime 在MFC 中自然也有她的同道:
  CTime::Format,这一对由于从面向对象哪里得到了赞助,用以写出的代码更觉优雅。

 

 

 

资料七

 

sprintf 用法总结(2009-08-25 09:36:24)标签:it   分类:C++ 
  sprintf,将各种类型的数据够造成字符串。

  sprintf是个变参函数,int sprintf(char *buffer,const char *format[,argument]...);除了前两个参数类型固定外,后面可以接任意多个参数,而它的精华,则在第二个参数:格式化字符串上。

  printf和sprintf都使用格式化字符串来指定串的格式,在格式串内部使用一些以“%”开头的格式说明符(format specification)来占据一个位置,在后边的变参列表中提供相应的变量,最终函数就会用相应位置的变量来替代那个说明符,产生一个调用者想要的字符串。

 一、格式化数字字符串

  sprintf最常见的应用之一莫过于把整数打印到字符串中,所以sprintf在大多数场合可以替代itoa.

    %-8d 代表宽度八位,左对齐(没有负号为右对齐),整数的十进制

  %x小写16进制  %X大写16进制

    符号扩展问题:参数压栈默认四字节,即8位16进制。应该让编译器做0扩展而不是符号扩展。

  如  sprintf(s,"%04X",(unsigned short)si);

    %o 8进制格式化字符串。

  控制浮点数打印格式,使用格式符"%f"控制,默认保留小数点后6位数字。

  %m.nf m表示打印的宽度,n表示小数点后的位数

  sprintf(s,"%m.nf",i)其中i 必须为浮点类型的

二、字符/ASCII码对照

  %c打印一个整数,可以看到整数所对应的ASCII值

  for(int i=32 ;i<127;i++)
  {
    printf("[%c]:%3d 0x%#04X/n",i,i,i);
  }

 #与%X合用时自动为16进制数增加“0X”前缀。

三、连接字符串

 可以在许多场合替代strcat,sprintf能够一次连接多个字符串。

 %s可以参照浮点数控制的%m.n m表示宽度,n表示从相应的字符串中最多取用的字符数,通常m没什么用。

  对于动态的,可以采用sprintf(s,"%.*s%.*s",7,a1,7,a2)或sprintf(s,"%.*s%.*s",sizeof(a1),a1,sizeof(a2),a2);  

四、打印地址信息

有时调试程序时,我们可能想查看某些变量或者成员的地址,由于地址或者指针也不过是个32 位的数,你完全可以使用打印无符号整数的”%u”把他们打印出来:
sprintf(s, "%u", &i);
不过通常人们还是喜欢使用16 进制而不是10 进制来显示一个地址:
sprintf(s, "%08X", &i);
然而,这些都是间接的方法,对于地址打印,sprintf 提供了专门的”%p”:
sprintf(s, "%p", &i);
我觉得它实际上就相当于:
sprintf(s, "%0*x", 2 * sizeof(void *), &i);

五、返回值

返回了本次函数调用最终打印到字符缓冲区中的字符数目。 
六、strftime

专门用于格式化时间字符串。需调用者指定缓冲区的最大长度。

strftime(s,sizeof(s),"%Y-%m-%d %H:%M:%S",localtime(&t));




资料八


sprintf

int sprintf ( char * str, const char * format, ... );
Write formatted data to string
Composes a string with the same text that would be printed if format was used on printf, but instead of being printed, the content is stored as a C string in the buffer pointed by str.

The size of the buffer should be large enough to contain the entire resulting string (see snprintf for a safer version).

A terminating null character is automatically appended after the content.

After the format parameter, the function expects at least as many additional arguments as needed for format.

Parameters

str
Pointer to a buffer where the resulting C-string is stored.
The buffer should be large enough to contain the resulting string.
format
C string that contains a format string that follows the same specifications as format in printf (see printf for details).
... (additional arguments)
Depending on the format string, the function may expect a sequence of additional arguments, each containing a value to be used to replace a format specifier in the format string (or a pointer to a storage location, for n).
There should be at least as many of these arguments as the number of values specified in the format specifiers. Additional arguments are ignored by the function.

Return Value

On success, the total number of characters written is returned. This count does not include the additional null-character automatically appended at the end of the string.
On failure, a negative number is returned.

Example

1
2
3
4
5
6
7
8
9
10
11
/* sprintf example */
#include <stdio.h>

int main ()
{
  char buffer [50];
  int n, a=5, b=3;
  n=sprintf (buffer, "%d plus %d is %d", a, b, a+b);
  printf ("[%s] is a string %d chars long\n",buffer,n);
  return 0;
}


Output:
[5 plus 3 is 8] is a string 13 chars long

See also



  • 34
    点赞
  • 192
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值