VC字符串格式化的用法(全面实用) - 一路探索者

时间:2024-02-18 18:54:03

一、基本介绍

1、printf()函数的语法

关于格式化字符串,我们从最基本的一个函数入手,这个函数是printf()。它的的声明如下:

int printf(

 const char *format [,

 argument]...

);

参数format

它用以格式控制,通过含%的字符串来实现,如”%d”。参数里的%可以不止1个。

其实,该参数中,还可以使用普通字符和转义字符,如”My%d\n”。

该参数内除了输出控制符和转义字符外,其余字符原样输出。

该参数的完整语法如下:

%[flags] [width] [.precision] [{h | l | ll | I | I32 | I64}]type

后面讲详细介绍这些语法。

参数argument

它是可选参数,不是必须的,可能是1个,2个……,这跟前边一个参数中%的数量有关。

返回值:若成功,返回打印字符串的数量;若失败,返回负数。

 

2、典型格式化字符串函数的基本用法

关于格式化字符串的C运行库函数较多,它们的格式化用法,跟printf()的用法大同小异。

典型的格式化字符串函数有如下:

printf, _printf_l, wprintf, _wprintf_l

sprintf, _sprintf_l, swprintf, _swprintf_l, __swprintf_l

scanf, _scanf_l, wscanf, _wscanf_l

sscanf, _sscanf_l, swscanf, _swscanf_l

(1)、第一组简介

它们输出类型,将字符串显示在屏幕。

示例

int i = 35;

printf("%d",i); //显示35

(2)、第二组简介

它们为输出类型,将格式化后的字符串保存在变量,而不显示在屏幕。

示例

char buffer[200], s[] = "computer";

sprintf(buffer, "My %s\n", s);

printf("%s", buffer); //显示My computer

(3)、第三组简介

它们为输入类型,从键盘输入,保存在变量。

int i, result;

float fp;

char  c, s[81];

wchar_t wc, ws[81];

result = scanf( "%d %f %c %C %80s %80S", &i, &fp, &c, &wc, s, ws );

printf("The number of fields input is %d\n", result);

printf("The contents are: %d %f %c %C %s %S\n", i, fp, c, wc, s, ws);

 

从键盘输入如下内容(最后还要按回车键):

71 98.6 h z Byte characters

然后将显示如下内容:

The number of fields input is 6

The contents are: 71 98.599998 h z Byte characters

(4)、第四组简介

它们为输入类型,不从键盘输入,将给定的字符串按指定格式,保存在变量。

char  tokenstring[] = "15 12 14...";

char  s[81];

char  c;

int   i;

float fp;

 

sscanf(tokenstring, "%80s", s);

sscanf(tokenstring, "%c", &c); 

sscanf(tokenstring, "%d", &i); 

sscanf(tokenstring, "%f", &fp);

  

printf("String    = %s\n", s);

printf("Character = %c\n", c);

printf("Integer:  = %d\n", i);

printf("Real:     = %f\n", fp);

 

显示如下内容:

String    = 15

Character = 1

Integer:  = 15

Real:     = 15.000000

(5)、sscanf()与sprintf()的区别

它们都不需要硬件输入输出,且最终结果都是保存在变量中,但两者还是有区别的。Sscanf()的最大特点是要给定一字符串(第1个参数),在该值基础上格式化输出;而sprintf()则不需要给定一字符串,直接将格式化的部分的内容保存在变量。

 

二、printf()函数的语法详解

该函数的第1个参数是输入参数,是字符串类型,用于格式化字符串,它的完整语法如下:

%[flags] [width] [.precision] [{h | l | ll | I | I32 | I64}]type

其中%是格式标志符号,是必须的且固定不变; [……] 部分是可选的;type表示数据类型,和%一样,也是必须的。

1、[flags]部分的用法

它为标志符号,共有6个:–、+、0、空格符(\' \')、#、*

(1)、“–”标志符号

    在缺省情况下,输出结果采用右对齐;若使用了“-”标志,则在给定的字段宽度内采用左对齐。

(2)、“+”标志符号

如果输出值是有符号整数类型,则在输出值前面加上正负符号(+或-)。

(3)、“0”标志符号

如果width以“0”为前缀,则会添加0直到达到最小宽度为止。

注意:以下两种情况,“0”标志符号功能将被忽略。

A、如果使用了“-”标志,则“0”标志符号功能不在起作用。

B、如果“0”是用整数格式指定的(i、u、x、X、o、d),并且还提供了精度规范(例如,%04.d), “0”标志符号功能也不在起作用。

(4)、blank(空格)标志符号

如果输出值是带符号且为正的正数,则在输出值的前面加上一个空白;如果同时出现空白和+标志,空白将被忽略。

这里的blank标志符号,是针对带符号的正整数而言。对于字符串的空格,则直接使用’ ’字符。

(5)、“#”标志符号

当与o、x或X格式一起使用时,分别输出0、0x或0X作为任何非零输出值的前缀,分别表示八进制数、十六进制数、十六进制数。前缀0x与0X都表示十六进制数。

 

(6)、“*”标志符号

“*”要占一个变量的位置,不过它被忽略,从“*”的下一个位置开始取值。整数类型支持这种功能,但是浮点数则不支持。

 

2、[width]部分的用法

    这个可选字段是宽度规范。宽度参数是一个非负的十进制整数,控制打印的最小字符数。如果输出值中的字符数小于指定的宽度,则会在值的左边或右边添加空格(若使用了“-”标志,则左对齐,右边补空格;否则右边对齐,左边补空格),直到达到最小宽度。

    一般情况下,宽度与“0”标志符号搭配使用,才有意义。如果width以“0”为前缀,则会添加0直到达到最小宽度为止(对于左对齐的数字没有用处)。

    宽度规范不会导致值被截断。如果输出值中的字符数大于指定的宽度,或者宽度未指定,则打印该值的所有字符(根据精度要求)。

 

3、[.precision]部分的用法

这个可选字段是精度规范。它指定一个非负的十进制整数,前面有一个句点,即“.”符号,它指定要打印的字符数、小数点位数或有效位数(请参阅精度值如何影响类型表)。

与宽度规范不同,精度规范可能导致输出值的截断或浮点值的舍入。

如果将精度指定为0,且要转换的值为0,则结果为不输出字符,参考如下:

printf( "%.0d", 0);  //结果为空值

    类型决定了精度的解释,当省略精度时,默认值如下表所示。

类型

含义

缺省值

a, A

精度指定小数点后的位数。

 

默认精度为6。如果精度为0,则不打印小数点,除非使用#标志。

c, C

非数值型数据,与精度无关。

字符直接打印出来。

d, i, u, o, x, X

精度指定要打印的最小数字个数。若参数中的数字个数小于精度,输出值将在左侧用零填充。若参数中的数字个数大于精度时,输出值为参数值。

默认精度为1。

 

e, E

精度指定小数点后的位数,最后打印的数字四舍五入。

默认精度为6;如果precision为0或句点(.)后面没有数字,则不打印小数点。

f

精度指定小数点后的位数。如果出现小数点,则小数点前至少出现一位数字。该值被四舍五入到适当的位数。

默认精度为6;如果精度为0,或者句点(.)后面没有数字,则不打印小数点。

g, G

精度指定打印的最大有效数字数。

 

将打印6个有效数字,末尾的零将被截断。

s, S

精度指定要打印的最大字符数,不打印超过精度的字符。

字符一直打印到遇到空字符为止。

 

4、[{h | l | ll | I | I32 | I64}]部分的用法

    type的可选前缀h、l、I、I32、I64和ll指定参数的“size”(长或短、32或64位、单字节字符或宽字符,取决于它们修改的类型说明符)。这些类型说明符前缀与printf函数或wprintf函数中的类型字符一起使用,以指定参数的解释,如下表所示。

    当h和l前缀作为字符使用时,是Microsoft扩展字符,而不是ansi的。

说明

前缀

类型说明

long int

l

d, i, o, x或X

long unsigned int

l

o, u, x或X

long long

l l

d, i, o, x或X

short int

h

d, i, o, x或X

short unsigned int

h

o, u, x或X

__int32

I32

d, i, o, x或X

unsigned __int32

I32

o, u, x或X

__int64

I64

d, i, o, x或X

unsigned __int64

I64

o, u, x或X

ptrdiff_t (在32位系统,为__int32类型;在64位系统,为__int64类型)

I

d, i, o, x或X

size_t (在32位系统,为__int32类型;在64位系统,为__int64类型)

I

o, u, x或X

long double

l

f

在printf函数中使用的单字节字符

h

 

c或C

在wprintf函数中使用的单字节字符

h

 

c或C

在printf函数中使用的宽字节字符

l

c或C

在wprintf函数中使用的宽字节字符

l

 

c或C

在printf函数中使用的单字节字符串

h

 

s或S

在wprintf函数中使用的单字节字符串

h

 

s或S

在printf函数中使用的宽字节字符串

l

 

s或S

在wprintf函数中使用的宽字节字符串

l

 

s或S

宽字节字符

w

c

宽字节字符串

w

s

 

printf函数和wprintf函数打印单字节或宽字符,请使用如下格式说明符。

输出字符类别

使用函数

格式控制符

单字节字符

printf

c, hc或hC

单字节字符

wprintf

c, hc或hC

宽字节字符

wprintf

c, lc, lC或 wc

宽字节字符

printf

c, lc, lC或wc

 

5、type部分的用法

    类型字符是唯一必需的格式字段,它出现在任何可选的格式字段之后。类型字符确定关联参数是被解释为字符、字符串还是数字。类型C、n、p和S,以及C和S与printf函数的行为,都是Microsoft扩展,不是ANSI兼容的。

类型

实际类型

输出格式

c

int 或 wint_t

当使用printf函数时,指定一个单字节字符;当使用wprintf函数时,指定一个宽字符。

注:wint_t为unsigned short

C

int 或 wint_t

当使用printf函数一起时,指定一个宽字符;当使用wprintf函数时,指定一个单字节字符。

d

int

有符号十进制整数。

i

int

有符号十进制整数。

o

unsigned int

无符号八进制整数。

u

unsigned int

无符号十进制整数。

x

unsigned int

无符号十六进制整数,使用abcdef。

X

unsigned int

无符号十六进制整数,使用ABCDEF。

e

double

采用科学计数法,形式为[-]d.dddd e [sign]dd[d]的带符号值。其中d为单个十进制数,dddd为一个或多个十进制数,dd[d]为两个或三个十进制数,符号为+或-。

E

double

和e格式一样,只是输出结果用E替换e。

f

double

形式为[-]dddd.dddd的带符号值,其中dddd是一个或多个十进制数字。小数点前的位数取决于数字的大小,小数点后的位数取决于要求的精度。

g

double

以f或e格式打印带符号值,这取决于哪个更短。e格式仅在值的指数小于-4或大于或等于precision参数时使用。后面的零会被截断,小数点只在后面有一个或多个数字时才会出现。

G

double

与g格式相同,只是输出结果用E替换e除了E。

a

double

采用P计数法,形式为[−]0xh.hhhh P±dd的有符号十六进制双精度浮点值,其中h.hhhh为尾数的十六进制数字(用小写字母表示),dd为指数的一个或多个数字。精度指定点后的位数。

A

double

采用P计数法,形式为[−]0Xh.hhhh P±dd的有符号十六进制双精度浮点值,其中h.hhhh为尾数的十六进制数字(大写字母),dd为指数的一个或多个数字。精度指定小数点后的位数。

n

指向整型的指针

到目前为止成功写入流或缓冲区的字符数;该值存储在整数中,其地址作为参数给出。

p

指向任意型的指针

将打印十六进制数表示的变量地址值。

s

字符串

当与printf函数一起使用时,指定一个单字节字符串;当与wprintf函数一起使用时,指定宽字符字符串。字符将一直打印到第一个空字符或直到达到精度值为止。

S

字符串

当与printf函数一起使用时,指定宽字符字符串;当与wprintf函数一起使用时,指定一个单字节字符串。字符将一直打印到第一个空字符或直到达到精度值为止。

 

注意:如果对应于%s或%S的参数是空指针,“(null)”将被打印。

注意:在所有指数格式中,默认显示的指数位数是3。使用_set_output_format函数,可以将显示的数字数设置为2,如果exponent的大小需要,则扩展为3。

安全注意:%n格式本质上是不安全的,默认情况下是禁用的;如果在格式字符串中遇到%n,将按照参数验证中所述调用无效的参数处理程序。要启用%n支持,请使用_set_printf_count_output函数。

 

三、printf()函数的用法

现在大多的程序是在MFC代码,CString类的Format()成员的用法,跟printf()函数一致。因此,示例采用MFC程序。

可能要包含如下文件:#include <stdio.h>

1、[flags]部分的用法

(1)、“–”标志符号

CString strTemp1;

strTemp1.Format("|%15s|","1234567890");

//为了观看效果直观,需要加“参照物”,如这里的\'|\'

//给定15个字符长度,但这里只有10个字符,不够15个;

//由于没有加“–”,则缺省为右边对齐,左边补空格。 

MessageBox(strTemp1); //结果为|     1234567890|

 

strTemp1.Format("|%-15s|","1234567890");

//给定15个字符长度,但这里只有10个字符,不够15个,则左对齐,右边补空格。     

MessageBox(strTemp1); //结果为|1234567890   

 

(2)、“+”标志符号

CString strTemp2;

strTemp2.Format("%+d",200);

MessageBox(strTemp2); //结果为+200

 

strTemp2.Format("%+d",-200);

MessageBox(strTemp2); //结果为-200

 

strTemp2.Format("%d",-200); //对于负数,可以不加“+”

MessageBox(strTemp2); //结果为-200

 

(3)、“0”标志符号

CString strTemp3;

strTemp3.Format("%03d",4);  

//当前字符串的宽度为3

MessageBox(strTemp3); //结果为004

 

strTemp3.Format("%-03d",4); 

//使用“-”标志后,“0”标志符号功能将被忽略

MessageBox(strTemp3); //结果为4

 

strTemp3.Format("%03.d",4); 

//使用整数格式指定的(i、u、x、X、o、d),并且还提供了精度规范(例如,%04.d),

//“0”标志符号功能也不在起作用。

MessageBox(strTemp3); //结果为4

 

(4)、空格标志符号

CString strTemp4;

strTemp4.Format("%d",500);//正号用空格替代

MessageBox(strTemp2); //结果为500

 

(5)、“#”标志符号

CString strTemp5;

strTemp5.Format("%#o",35);

//输出一个八进制数,将十进制数转换为八进制数

MessageBox(strTemp5); //结果为043,前缀为零而非字母o

 

strTemp5.Format("%#x",35);

//输出一个十六进制数,将十进制数转换为十六进制数

MessageBox(strTemp5); //结果为0x23

 

strTemp5.Format("%#X",35); //前缀0x与0X都表示十六进制数

//输出一个十六进制数,将十进制数转换为十六进制数 

MessageBox(strTemp5); //结果为0X23

 

strTemp5.Format("%#x",0x35);

//输出一个16进制数,这里0x35本身就是十六进制数

MessageBox(strTemp5); //结果为0x35

 

(6)、“*”标志符号

CString strTemp6;

strTemp6.Format("%*d,%d",12,28,89);

//首先,“*”要占一个变量的位置,不过它被忽略;

//因此,从“*”的下一个位置开始取值;

//这里“*”对应的数是28,但被忽略;后边还有两个%d,则分别对应28和89

MessageBox(strTemp6); //结果为28,89   

 

//strTemp6.Format("%*f,%f",28.45,67.26,83.02);

//float类型不支持“*”功能

//MessageBox(strTemp6);

 

2、[width]部分的介绍

CString strTemp;

strTemp.Format("%d",4); 

//不指定宽度,输出本身。

MessageBox(strTemp); //结果为4

 

strTemp.Format("%2d",4);

//指定宽度,但不指定前缀“0”,也输出本身。

MessageBox(strTemp); //结果为4

 

strTemp.Format("%02d:%02d:%02d:%03d",4,52,6,21);

//即指定了宽度,又指定了指定前缀“0”,才右意义。

MessageBox(strTemp); //结果为04:52:06:021

//其中小时部分“4”,不足两位,则补齐为“04”;

//其中分钟部分“52”,本身就是两位,则不变。

 

strTemp.Format("%-03d",4);   

//使用“-”标志后,“0”标志符号功能将被忽略

MessageBox(strTemp); //结果为4

 

strTemp.Format("%8s","abcdefghijk"); 

//这里指定输出值的字符数为8,而实际给定的字符数为11;

//这种输出值中的字符数大于指定的宽度,输出值不会被截断。

MessageBox(strTemp); //结果为abcdefghijk,而不是abcdefgh

      

strTemp.Format("|%15s|","1234567890"); //未使用“–”标志符号

//为了观看效果直观,需要加“参照物”,如这里的\'|\'

//给定15个字符长度,但这里只有10个字符,不够15个;

//由于没有加“–”,则缺省为右边对齐,左边补空格。 

MessageBox(strTemp); //结果为|     1234567890|

 

strTemp.Format("|%-15s|","1234567890"); //使用了“–”标志符号

//给定15个字符长度,但这里只有10个字符,不够15个,则左对齐,右边补空格。     

MessageBox(strTemp); //结果为|1234567890      

 

3、[.precision]部分的介绍

float fVal = 45.27;

CString strTemp;

strTemp.Format("%f",fVal);    

//不指定精度,缺省情况下,float类型的变量会显示6位小数。

MessageBox(strTemp); //结果为45.270000

strTemp.Format("%.3f",fVal); 

//指定输出3位小数

MessageBox(strTemp); //结果为45.270

strTemp.Format("%.2f",fVal); 

//指定输出2位小数

MessageBox(strTemp); //结果为45.27

strTemp.Format("%.1f",fVal); 

//指定输出1位小数,最后一位小数执行四舍五入

MessageBox(strTemp); //结果为45.3

 

strTemp.Format("%.0d",0);     

//精度指定为0,且要转换的值为0,则结果为不输出字符

MessageBox(strTemp); //结果为空值

 

strTemp.Format("%.2d",452);

//参数452的数字个数为3,精度为2

//参数中的数字个数大于精度,输出值为参数值。

MessageBox(strTemp); //结果为452

strTemp.Format("%.5d",452);

//参数452的数字个数为3,精度为5

//参数中的数字个数小于精度,输出值将在左侧用零填充。

MessageBox(strTemp); //结果为00452

 

4、[{h | l | ll | I | I32 | I64}]部分的介绍

int iVal = -269;

//int的范围为-2147483648-2147483647

unsigned int uVal = 248;

//unsigned int的范围为0-4294967295

long long llVal = -9223372036854775808;

//long long的范围为-9223372036854775808-9223372036854775807

__int32 __iVal32 = 678;

//__int32等效为int

__int64 __iVal64 = 9223372036854775807;

//__int64等效为long long

unsigned __int64 u__iVal64 = 18446744073709551615;

//unsigned __int64等效为unsigned long long

//unsigned __int64的范围为0-18446744073709551615

//18446744073709551615(0xffffffffffffffff)

long double dVal = 67.34576899;

 

char cChar = \'D\';

WCHAR wChar = \'F\';

 

char* sStr = "abcd";

WCHAR* wStr = L"efgh"; //宽字符串要以L为前缀

 

CString strTemp;

strTemp.Format("%d",iVal);         

MessageBox(strTemp); //结果为-269

strTemp.Format("%ld",iVal);       

MessageBox(strTemp); //结果为-269

strTemp.Format("%u",uVal);       

MessageBox(strTemp); //结果为248

strTemp.Format("%u",iVal);//类型不一致,虽不报错,但结果错误   

MessageBox(strTemp); //结果为4294967027

//4294967027 = 4294967295+(-269)

 

strTemp.Format("%lld",llVal); //ll对应long long类型 

MessageBox(strTemp); //结果为-9223372036854775808

strTemp.Format("%I32d",__iVal32); //I32对应int类型 

MessageBox(strTemp); //结果为678

strTemp.Format("%I64d",__iVal64); //I64对应long long类型 

MessageBox(strTemp); //结果为9223372036854775808

strTemp.Format("%I64u",u__iVal64); //I64也对应unsigned long long类型 

MessageBox(strTemp); //结果为18446744073709551615

 

strTemp.Format("%f",dVal); 

MessageBox(strTemp); //结果为67.345769

strTemp.Format("%lf",dVal);

MessageBox(strTemp); //结果为67.345769

 

strTemp.Format("%c",cChar); //“c”为单字节字符

MessageBox(strTemp); //结果为D

strTemp.Format("%hc",cChar); //“hc”为单字节字符

MessageBox(strTemp); //结果为D

strTemp.Format("%lc",wChar); //“lc”为宽字符

MessageBox(strTemp); //结果为F

 

strTemp.Format("%s",sStr); //“s”为单字节字符串

MessageBox(strTemp); //结果为abcd

strTemp.Format("%hs",sStr); //“hs”为单字节字符串

MessageBox(strTemp); //结果为abcd

strTemp.Format("%ls",wStr); //“ls”为宽字节字符串

MessageBox(strTemp); //结果为efgh

 

strTemp.Format("%wc",wChar); //“wc”为宽字符

MessageBox(strTemp); //结果为F

strTemp.Format("%ws",wStr); //“ws”为宽字节字符串

MessageBox(strTemp); //结果为efgh

 

5、type部分的介绍

char cChar = \'D\';

WCHAR wChar = \'F\';

char* sStr = "abcd";

WCHAR* wStr = L"efgh"; //宽字符串要以L为前缀

CString strTemp;

strTemp.Format("%c",cChar); //“c”为单字节字符

MessageBox(strTemp); //结果为D

strTemp.Format("%C",wChar); //“C”为宽字符

MessageBox(strTemp); //结果为F

strTemp.Format("%s",sStr); //“s”为单字节字符串

MessageBox(strTemp); //结果为abcd

strTemp.Format("%S",wStr); //“S”为宽字符串

MessageBox(strTemp); //结果为efgh

 

int iVal = -248;

//int的范围为-2147483648-2147483647

unsigned int uVal = 248;

//unsigned int的范围为0-4294967295

strTemp.Format("%d",iVal); //“d”为int

MessageBox(strTemp); //结果为-248

strTemp.Format("%u",uVal); //“u”为unsigned int

MessageBox(strTemp); //结果为248

strTemp.Format("%x",uVal); //“x”为无符号十六进制整数

MessageBox(strTemp); //结果为f8

strTemp.Format("%X",uVal); //“X”为无符号十六进制整数

MessageBox(strTemp); //结果为F8

 

double dVal = 41.25;

strTemp.Format("%A",dVal);

//采用P计数法,底数为2,p+5为2的5次方

MessageBox(strTemp); //结果为0X1.4A0000P+5

strTemp.Format("%a",dVal);

//采用P计数法,底数为2,p+5为2的5次方

MessageBox(strTemp); //结果为0x1.4a0000p+5

strTemp.Format("%E",dVal);

//采用科学计数法,底数为10,E+001为10的1次方    

MessageBox(strTemp); //结果为4.125000E+001

strTemp.Format("%e",dVal);

//采用科学计数法,底数为10,E+001为10的1次方    

MessageBox(strTemp); //结果为结果为4.125000e+001

strTemp.Format("%.3e",dVal);

//采用科学计数法,底数为10,E+001为10的1次方    

MessageBox(strTemp); //结果为结果为4.125e+001

strTemp.Format("%f",dVal);

//缺省情况下,小数位保留6位 

MessageBox(strTemp); //结果为结果为41.250000

strTemp.Format("%.2f",dVal);

//小数位保留两位    

MessageBox(strTemp); //结果为结果为41.25

strTemp.Format("%g",dVal);

//选取f与e输出结果的简洁值,41.25比4.125000e+001简洁

MessageBox(strTemp); //结果为结果为41.25

strTemp.Format("%G",dVal);

//选取f与E输出结果的简洁值,41.25比4.125000E+001简洁

MessageBox(strTemp); //结果为结果为41.25

 

void* pVoid = "ASD";

strTemp.Format("%p",pVoid);

//输出变量的地址值。

MessageBox(strTemp); //结果为结果为012BE250

posted on 2021-05-20 09:34  一路探索者  阅读(198)  评论(0编辑  收藏  举报