printf()、sprintf()、vprintf()、vsprintf()、有符号|无符号数

4 篇文章 0 订阅
2 篇文章 0 订阅

http://sumsung753.blog.163.com/blog/static/14636450120112151092934/

一、printf()

printf()函数优点在于可以格式化输出!
printf()是一个函数,输出字符串,而print是一个语言结构,总是返回true(1),而echo也是语言结构,返回无效。

total=12.4echoechoTotalamountis total.”;
输出:Total amount is 12.4.
换回printf则为这样表达:
printf(“Total amount is %s.”, total);Totalamountis12.4. total代替。
事实上,printf()的表达式是这样:
string sprintf ( string format[,mixed args [, mixed $… ]] )
函数里面第一参数是格式化字符串,里面可以有n个%(转换说明),每个转换说明将按顺序被一个个重新格式化的参数代替,%后面至少带一参量–type(类型码),表示一定含义,请看参量表:
类型码 含义
b 解释为整数并作为二进制输出
c 解释为整数并作为字符表示输出(ASCII码)
d 解释为整数并作为整数输出
e 解释为浮点数输出
f 解释为双精度并作为浮点数输出
o 解释为整数并作为八进制数输出
s 解释为字符串并为字符串输出
u 解释为无符号整数输出
g 解释自动选择合适的表示法
p 解释为指针的值
x 解释为整数并作为带有小写字母a-f的十六进制数输出
X 解释为整数并作为带有大写字母A-F的十六进制数输出

例子1:
n=43951789; u = -43951789;
$c = 65; // ASCII 65 is ‘A’

printf(“%%b = ‘%b’\n”, n);//printf( c); // %c = ‘A’,作为ascii字符输出, 与chr()函数一样
printf(“%%d = ‘%d’\n”, n);//printf( n); // %e = ‘4.39518e+7’,科学记数法
printf(“%%u = ‘%u’\n”, n);//printf( u); // %u = ‘4251015507’,无符号数,负
printf(“%%f = ‘%f’\n”, n);//printf( n); // %o = ‘247523255’,八进制
printf(“%%s = ‘%s’\n”, n);//printf( n); // %x = ‘29ea6ad’,十六进制,小写字母
printf(“%%X = ‘%X’\n”, $n); // %X = ‘29EA6AD’,十六进制,大写字母

printf(“%%+d = ‘%+d’\n”, n);//printf( u); // %+d = ‘-43951789’,在一个负整数上作+

每个转换说明遵守同样的格式,如下:
%[‘padding_character][-][width][.precision]type
所有的转换说明都是以%开始,如果想打印一个%符号,必须用%%。
参数’padding_character(填充字符)是可选,它将被用来填充变量直至所指定的宽度,该参数的作用就在变量前面填充,.默认的填充字符是一个空格,如果指定0或者空格,就不需要 ‘单引号作为前缀,其他字符就必须指定 ’ 作为前缀。
参数 - 是可选,它指左对齐,默认是右对齐。
参数width是指被替换的变量的长度。
参数precision表示以小数点开始,它指明小数点后要显示的位数。

说明:
(1). 可以在”%”和字母之间插进数字表示最大宽度。
 ①例如: %3d 表示输出3位整型数, 不够3位右对齐。
 ②%9.2f 表示输出宽度为9的浮点数, 其中小数位为2, 整数位为6, 小数点占一位, 不够9位右对齐。
 ③%8s 表示输出8个字符的字符串, 不够8个字符右对齐。
 ④如果字符串的长度、或整型数位数超过说明的场宽, 将按其实际长度输出。
 ⑤浮点数, 若整数部分位数超过了说明的整数位宽度, 将按实际整数位输出;
 ⑥小数部分位数超过了说明的小数位宽度, 则按说明的宽度以四舍五入输出。
 ⑦若想在输出值前加一些0, 就应在场宽项前加个0。
   例如: %04d 表示在输出一个小于4位的数值时, 将在前面补0使其总宽度为4位。
⑧如果用浮点数表示字符或整型量的输出格式, 小数点后的数字代表最大宽度, 小数点前的数字代表最小宽度。
   例如: %6.9s 表示显示一个长度不小于6且不大于9的字符串。若大于9, 则第9个字符以后的内容将被删除。

(2). 可以在”%”和字母之间加小写字母l, 表示输出的是长型数。
①例如: %ld 表示输出long整数
②%lf 表示输出double浮点数

(3). 可以控制输出左对齐或右对齐, 即在”%”和字母之间加入一个”-” 号可说明输出为左对齐, 否则为右对齐。
  ①例如: %-7d 表示输出7位整数左对齐
  ②%-10s 表示输出10个字符左对齐

(4). 一些特殊规定字符
①\n 换行
 ②\f 清屏并换页
 ③\r 回车
 ④\t Tab符
 ⑤\xhh 表示一个ASCII码用16进表示,
  其中hh是1到2个16进制数

例子2:
year=2011; month = 3;
day=15; isodate = sprintf("%04d-%02d-%02d", year, month, day); //#1,%04d表示四位整数,如果变量不够四位,左边的空位(原始数字右对齐)将用0代替。  
echo
isodate;
输出:2011-03-15,

1的地方可以改为: isodate=sprintf(" year, month, day); //%’15d表示五位整数,不够倍数用1这个符号代替,输出:12011-03-15(因为2011不够五位)。还可以改成: isodate=sprintf(" year, month, day); //%’1-6d表示6位数,不够的右空位1代替(原始四位数左对齐),输出:201111-03-15。

例子3:
total=201.1; myint = 201.44651;
string=iloveyou!;printf(Totalamountis total); //输出:Total amount is 201.10,小数点两位,不够位数右对齐,用默认空格代替空位。
printf(“Total amount is %7.2f”, total);//Totalamountis201.10printf(Myintis myint); // Myint is 201.45,保留两位小数,四舍五入最小数点最后一位,整数部份最少一位,按实际输出。
printf(“The strings is %1.2s”, total);//Thestringsis201.212printf(Thestringsis string); // The strings is i lov,输出字数为3。

例子4:
s=monkey; t = ‘many monkeys’;

printf(“[%s]\n”, s);//[monkey]printf([ s); // [ monkey],原字符串右对齐,左边不够位数用空格填
printf(“[%-10s]\n”, s);//[monkey]printf([ s); // [0000monkey],右对齐,不够位数在字符串中用0填
printf(“[%’#10s]\n”, s); // [####monkey],用特别字符填不足位  
printf(“[%10.10s]\n”,
t); // 输出字数为10,把多余字截掉

二、sprintf()
string sprintf ( string format [, mixed args [, mixed …]] )
Returns a string produced according to the formatting string format .

跟printf相似,但不打印,而是返回格式化后的文字,其他的与printf一样。

三、vprintf()
输出格式化字符串
int vprintf ( string format,array args )
根据 format (sprintf() 函数文档中有相关描述)参数指定的格式,在一个格式化字符串中显示多个值。

作用与 printf() 函数类似,但是接收一个数组参数,而不是一系列可变数量的参数。
vprintf(“%04d-%02d-%02d”, explode(‘-‘, ‘1988-8-1’)); // 1988-08-01

四、vsprintf()
返回格式化字符串
string vsprintf ( string format,array args )
作用与 sprintf() 函数类似,但是接收一个数组参数,而不是一系列可变数量的参数。
根据 format (sprintf() 函数文档中有相关描述)参数指定的格式,在一个字符串中返回一系列值。
print vsprintf(“%04d-%02d-%02d”, explode(‘-‘, ‘1988-8-1’)); // 1988-08-01

*五、有符号数|无符号数
在C/C++里面不同类的数据是不能比较的,要从低级类型转换为高级类型 。
比如char 和 int 比较 要转换为int ,
比如int 和float 比较 要转换为float ,

关于有符号数和无符号数 机器中表示数都用二进制表示。二进制的最高位表示符号:1为负,0为正,而无符号数则不存在符号位-1的最高为1 ,而5的最高为0,比较大小时候转换为无符号数,所以转换后-1大于5。

main( ){
unsigned a=32768;
printf(“a=%d\n”,a);
}

答案是 a=-32768。

首先,unsigned是表示一个变量(或常数)是无符号类型。signed表示有符号。

unsigned & signed I

无符号数的数值范围0-65535,有符号数的数值范围在-32768- +32767之间.所以有符号运算比无符号运算耗资源。? 无符号数32768的二进制形式为1000 0000 0000 0000。

在转换为有符号数时。由于最高位表示符号数,因此可以理解其为一个负数。负数采用2的补码(two’s complement)表示。“要把内存中以补码形式存放的二进制码转换成十进制的负数步骤如下:
1.先对各位取反
2.将所得的二进制数转换成十进制数
3.因为最高位为1,因此在所得的十进制数前面加负号
4.对所求得的数再减1,即可

?按照上面的步骤:各位先取反,0111 1111 1111 1111 ;再转为十进制数,32767;再在所得的数前加负号,-32767;再减1,即为-32767-1=-32768.。

unsigned & signed Ⅱ

main(){ 
int b=-2;
 printf(“b=%u”,b);
}
答案是b=65534。

其具体步骤为:
先取-2的绝对值2的原码:0000 0000 0000 0010
将其转换为反码:1111 1111 1111 1101
加1补码:1111 1111 1111 1110
十进制形式就是无符号数:65534

http://blog.163.com/zhoumhan_0351/blog/static/39954227200972291615439/

16、易忽略的sprintf和printf用法

给你一个问题,要求将给定的字符串循环移位,(比如abc,变为bca),你怎么办呢?是利用数组来定义一个循环吗?倒也不失为一个方法。这里,我们介绍一种更为简洁的方法来处理它,对于同一类问题,有引玉作用。

Char a[6]=”abc”,b[6];

Char *s;

S=a;

Sprintf(b,”%s%c”,s+1,*s);

Puts(b);

是不是发现很简单?那么,我们这里就重点介绍一下sprintf吧!

sprintf 跟printf 在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,后者则直接在命令行上输出。这也导致sprintf 比printf 有用得多。

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

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 个字节就被不由分说地强行作为浮点数格式来解释了,乱套了。

3、字符/Ascii 码对照

我们知道,在C/C++语言中,char 也是一种普通的scalable 类型,除了字长之外,它与short,int,long 这些类型没有本质区别,只不过被大家习惯用来表示字符和字符串而已。于是,使用”%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);

}

4、连接字符串

sprintf 的格式控制串中既然可以插入各种东西,并最终把它们“连成一串”,自然也就能够连接字符串,从而在许多场合可以替代strcat,但sprintf 能够一次连接多个字符串(自然也可以同时在它们中间插入别的内容,总之非常灵活)。比如:

char* who = “I”;

char* whom = “CSDN”;

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

strcat 只能连接字符串(一段以’\0’结尾的字符数组或叫做字符缓冲,null-terminated-string),但有时我们有两段字符缓冲区,他们并不是以’\0’结尾。比如许多从第三方库函数中返回的字符数组,从硬件或者网络传输中读进来的字符流,它们未必每一段字符序列后面都有个相应的’\0’来结尾。如果直接连接,不管是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);

5、利用sprintf 的返回值

spritnf 返回了本次函数调用最终打印到字符缓冲区中的字符数目。当sprinf 调用结束以后,你无须再调用一次strlen 便已经知道了结果字符串的长度。如:

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

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

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

include “stdio.h”

include “time.h”

include “stdlib.h”

int main() {

srand(time(0)); //和rand一起用,给出种子起始值

char s[64];

int offset = 0;

for(int i = 0; i < 10; i++) {

offset += sprintf(s + offset, “%d,”, rand() % 100);

//printf(“%d\n”,offset);

//puts(s);

//puts(“\n”);

}

s[offset - 1] = ‘\n’;//将最后的逗号换成回车

printf(s);

return 0;

}

设想当你从数据库中取出一条记录,然后希望把他们的各个字段按照某种规则连接成一个字符串时,就可以使用这种方法,从理论上讲,他应该比不断的strcat 效率高,因为strcat 每次调用都需要先找到最后的那个’\0’的位置,而在上面给出的例子中,我们每次都利用sprintf 返回值把这个位置直接记下来了。

6、使用sprintf 的常见问题

sprintf 是个变参函数,出问题通常就是能导致程序崩溃的内存访问错误。

1)第一个参数的长度太短了,给在一点就好了。而打印字符串时,尽量使用”%.ns”的形式指定最大字符数。

2)变参对应出问题

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

其是对应”*”的那些参数。

3)strftime

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.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值