sprintf
printf 可能是许多程序员在开始学习 C 语言时接触到的第二个函数(我猜第一个是 main),说
起来,自然是老朋友了,可是,你对这个老朋友了解多吗?你对它的那个孪生兄弟 sprintf 了解多
吗?在将各种类型的数据构造成字符串时,sprintf 的强大功能很少会让你失望
由于 sprintf 跟 printf 在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,
后者则直接在命令行上输出这也导致 sprintf 比 printf 有用得多所以本文着重介绍 sprintf,有时
也穿插着用用 pritnf
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 而不是补符号位):