zoukankan      html  css  js  c++  java
  • 转:sprintf与snprintf

    sprintf与snprintf

     

    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)。
  • 相关阅读:
    jchdl
    jchdl
    UVa 10256 (判断两个凸包相离) The Great Divide
    UVa 11168 (凸包+点到直线距离) Airport
    LA 2572 (求可见圆盘的数量) Kanazawa
    UVa 10652 (简单凸包) Board Wrapping
    UVa 12304 (6个二维几何问题合集) 2D Geometry 110 in 1!
    UVa 10674 (求两圆公切线) Tangents
    UVa 11796 Dog Distance
    LA 3263 (平面图的欧拉定理) That Nice Euler Circuit
  • 原文地址:https://www.cnblogs.com/yfz0/p/5834359.html
Copyright © 2011-2022 走看看